* ieee.c: Various changes to handle C++ reference types.
authorIan Lance Taylor <ian@airs.com>
Wed, 24 Jan 1996 01:26:21 +0000 (01:26 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 24 Jan 1996 01:26:21 +0000 (01:26 +0000)
binutils/ieee.c

index e1bef29136216698a4af4f9da9d89841d2044f09..f4be39e677b568d6bb9863d69fb57cb2e58a1db5 100644 (file)
@@ -39,6 +39,8 @@ struct ieee_block
   int kind;
   /* The source file name, for a BB5 block.  */
   const char *filename;
+  /* The index of the function type, for a BB4 or BB6 block.  */
+  unsigned int fnindx;
 };
 
 /* This structure is the block stack.  */
@@ -63,6 +65,10 @@ struct ieee_var
   unsigned long namlen;
   /* Type.  */
   debug_type type;
+  /* Slot if we make an indirect type.  */
+  debug_type *pslot;
+  /* Kind of variable (DEBUG_VAR_ILLEGAL if not a variable).  */
+  enum debug_var_kind variable;
 };
 
 /* This structure holds all the variables.  */
@@ -84,6 +90,8 @@ struct ieee_type
   debug_type type;
   /* Slot if this is type is referenced before it is defined.  */
   debug_type *pslot;
+  /* Slots for arguments if we make indirect types for them.  */
+  debug_type *arg_slots;
   /* If this is a bitfield, this is the size in bits.  If this is not
      a bitfield, this is zero.  */
   unsigned long bitsize;
@@ -115,19 +123,10 @@ struct ieee_tag
   debug_type type;
   /* The tagged type is an indirect type pointing at this slot.  */
   debug_type slot;
-};
-
-/* This structure holds a linked list of functions with their argument
-   types, so that we can convert them to C++ methods if necessary.  */
-
-struct ieee_function
-{
-  /* Next function.  */
-  struct ieee_function *next;
-  /* This function name.  */
-  const char *name;
-  /* The function type.  */
-  debug_type type;
+  /* This is an array of slots used when a field type is converted
+     into a indirect type, in case it needs to be later converted into
+     a reference type.  */
+  debug_type *fslots;
 };
 
 /* This structure holds the information we pass around to the parsing
@@ -151,8 +150,6 @@ struct ieee_info
   struct ieee_types types;
   /* The list of tagged structs.  */
   struct ieee_tag *tags;
-  /* The list of functions.  */
-  struct ieee_function *functions;
 };
 
 /* Basic builtin types, not including the pointers.  */
@@ -268,6 +265,10 @@ static boolean ieee_read_cxx_misc
   PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
 static boolean ieee_read_cxx_class
   PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
+static boolean ieee_read_cxx_defaults
+  PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
+static boolean ieee_read_reference
+  PARAMS ((struct ieee_info *, const bfd_byte **));
 static boolean ieee_require_asn
   PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *));
 static boolean ieee_require_atn65
@@ -885,7 +886,6 @@ parse_ieee (dhandle, abfd, bytes, len)
   info.types.alloc = 0;
   info.types.types = NULL;
   info.tags = NULL;
-  info.functions = NULL;
   for (i = 0; i < BUILTIN_TYPE_COUNT; i++)
     info.types.builtins[i] = DEBUG_TYPE_NULL;
 
@@ -965,7 +965,8 @@ parse_ieee_bb (info, pp)
   const char *name;
   unsigned long namlen;
   char *namcopy;
-           
+  unsigned int fnindx;
+
   block_start = *pp;
 
   b = **pp;
@@ -975,6 +976,8 @@ parse_ieee_bb (info, pp)
       || ! ieee_read_id (info, pp, &name, &namlen))
     return false;
 
+  fnindx = (unsigned int) -1;
+
   switch (b)
     {
     case 1:
@@ -1003,8 +1006,7 @@ parse_ieee_bb (info, pp)
       /* BB4: Global function.  */
       {
        bfd_vma stackspace, typindx, offset;
-       debug_type type, return_type;
-       struct ieee_function *func;
+       debug_type return_type;
 
        if (! ieee_read_number (info, pp, &stackspace)
            || ! ieee_read_number (info, pp, &typindx)
@@ -1015,22 +1017,21 @@ parse_ieee_bb (info, pp)
 
        if (typindx < 256)
          {
-           type = ieee_builtin_type (info, block_start, typindx);
-           if (type == NULL)
+           return_type = ieee_builtin_type (info, block_start, typindx);
+           if (return_type == DEBUG_TYPE_NULL)
              return false;
-           return_type = type;
          }
        else
          {
            typindx -= 256;
            if (! ieee_alloc_type (info, typindx, true))
              return false;
-           type = info->types.types[typindx].type;
-           if (debug_get_type_kind (info->dhandle, type)
-               != DEBUG_KIND_FUNCTION)
-             return_type = type;
-           else
-             return_type = debug_get_return_type (info->dhandle, type);
+           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);
@@ -1039,13 +1040,6 @@ parse_ieee_bb (info, pp)
        if (! debug_record_function (info->dhandle, namcopy, return_type,
                                     true, offset))
          return false;
-
-       func = (struct ieee_function *) xmalloc (sizeof *func);
-       memset (func, 0, sizeof *func);
-       func->next = info->functions;
-       info->functions = func;
-       func->name = namcopy;
-       func->type = type;
       }
       break;
 
@@ -1109,6 +1103,7 @@ parse_ieee_bb (info, pp)
                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)
@@ -1184,6 +1179,7 @@ parse_ieee_bb (info, pp)
   info->blockstack.bsp->kind = b;
   if (b == 5)
     info->blockstack.bsp->filename = namcopy;
+  info->blockstack.bsp->fnindx = fnindx;
   ++info->blockstack.bsp;
 
   return true;
@@ -1319,6 +1315,7 @@ parse_ieee_ty (info, pp)
   bfd_vma typeindx, varindx, tc;
   PTR dhandle;
   boolean tag, typdef;
+  debug_type *arg_slots;
   unsigned long type_bitsize;
   debug_type type;
 
@@ -1371,6 +1368,7 @@ parse_ieee_ty (info, pp)
 
   tag = false;
   typdef = false;
+  arg_slots = NULL;
   type_bitsize = 0;
   switch (tc)
     {
@@ -1691,6 +1689,7 @@ parse_ieee_ty (info, pp)
        debug_type rtype;
        bfd_vma nargs;
        boolean present;
+       struct ieee_var *pv;
 
        /* FIXME: We ignore the attribute and the argument names.  */
 
@@ -1708,6 +1707,19 @@ parse_ieee_ty (info, pp)
          }
        while (present);
 
+       pv = info->vars.vars + varindx;
+       if (pv->namlen > 0
+           && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
+         {
+           /* Set up the return type as an indirect type pointing to
+               the variable slot, so that we can change it to a
+               reference later if appropriate.  */
+           pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
+           *pv->pslot = rtype;
+           rtype = debug_make_indirect_type (dhandle, pv->pslot,
+                                             (const char *) NULL);
+         }
+
        type = debug_make_function_type (dhandle, rtype, (debug_type *) NULL,
                                         false);
       }
@@ -1815,6 +1827,7 @@ parse_ieee_ty (info, pp)
       /* Procedure with compiler dependencies.  FIXME: This is an
          extern declaration, which we have no way of representing.  */
       {
+       struct ieee_var *pv;
        bfd_vma attr, frame_type, push_mask, nargs, level, father;
        debug_type rtype;
        debug_type *arg_types;
@@ -1823,6 +1836,8 @@ parse_ieee_ty (info, pp)
 
        /* FIXME: We ignore almost all this information.  */
 
+       pv = info->vars.vars + varindx;
+
        if (! ieee_read_number (info, pp, &attr)
            || ! ieee_read_number (info, pp, &frame_type)
            || ! ieee_read_number (info, pp, &push_mask)
@@ -1863,12 +1878,46 @@ parse_ieee_ty (info, pp)
                  }
              }
 
+           /* If there are any pointer arguments, turn them into
+               indirect types in case we later need to convert them to
+               reference types.  */
+           for (i = 0; i < nargs; i++)
+             {
+               if (debug_get_type_kind (dhandle, arg_types[i])
+                   == DEBUG_KIND_POINTER)
+                 {
+                   if (arg_slots == NULL)
+                     {
+                       arg_slots = ((debug_type *)
+                                    xmalloc (nargs * sizeof *arg_slots));
+                       memset (arg_slots, 0, nargs * sizeof *arg_slots);
+                     }
+                   arg_slots[i] = arg_types[i];
+                   arg_types[i] =
+                     debug_make_indirect_type (dhandle,
+                                               arg_slots + i,
+                                               (const char *) NULL);
+                 }
+             }
+
            arg_types[nargs] = DEBUG_TYPE_NULL;
          }
        if (! ieee_read_number (info, pp, &level)
            || ! ieee_read_optional_number (info, pp, &father, &present))
          return false;
 
+       if (pv->namlen > 0
+           && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
+         {
+           /* Set up the return type as an indirect type pointing to
+               the variable slot, so that we can change it to a
+               reference later if appropriate.  */
+           pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
+           *pv->pslot = rtype;
+           rtype = debug_make_indirect_type (dhandle, pv->pslot,
+                                             (const char *) NULL);
+         }
+
        type = debug_make_function_type (dhandle, rtype, arg_types, varargs);
       }
       break;
@@ -1877,9 +1926,11 @@ parse_ieee_ty (info, pp)
   /* Record the type in the table.  If the corresponding NN record has
      a name, name it.  FIXME: Is this always correct?  */
 
-  if (type == NULL)
+  if (type == DEBUG_TYPE_NULL)
     return false;
 
+  info->vars.vars[varindx].type = type;
+
   if ((tag || typdef)
       && info->vars.vars[varindx].namlen > 0)
     {
@@ -1916,6 +1967,7 @@ parse_ieee_ty (info, pp)
     }
 
   info->types.types[typeindx].type = type;
+  info->types.types[typeindx].arg_slots = arg_slots;
   info->types.types[typeindx].bitsize = type_bitsize;
 
   /* We may have already allocated type as an indirect type pointing
@@ -1937,7 +1989,7 @@ parse_ieee_atn (info, pp)
 {
   const bfd_byte *atn_start, *atn_code_start;
   bfd_vma varindx;
-  boolean zeroindx;
+  struct ieee_var *pvar;
   debug_type type;
   bfd_vma atn_code;
   PTR dhandle;
@@ -1961,7 +2013,7 @@ parse_ieee_atn (info, pp)
 
   if (varindx == 0)
     {
-      zeroindx = true;
+      pvar = NULL;
       name = "";
       namlen = 0;
     }
@@ -1973,7 +2025,6 @@ parse_ieee_atn (info, pp)
   else
     {
       varindx -= 32;
-      zeroindx = false;
       if (varindx >= info->vars.alloc
          || info->vars.vars[varindx].name == NULL)
        {
@@ -1981,14 +2032,40 @@ parse_ieee_atn (info, pp)
          return false;
        }
 
-      info->vars.vars[varindx].type = type;
+      pvar = info->vars.vars + varindx;
+
+      pvar->type = type;
 
-      name = info->vars.vars[varindx].name;
-      namlen = info->vars.vars[varindx].namlen;
+      name = pvar->name;
+      namlen = pvar->namlen;
     }
 
   dhandle = info->dhandle;
 
+  /* If we are going to call debug_record_variable with a pointer
+     type, change the type to an indirect type so that we can later
+     change it to a reference type if we encounter a C++ pmisc 'R'
+     record.  */
+  if (pvar != NULL
+      && type != DEBUG_TYPE_NULL
+      && debug_get_type_kind (dhandle, type) == DEBUG_KIND_POINTER)
+    {
+      switch (atn_code)
+       {
+       case 1:
+       case 2:
+       case 3:
+       case 8:
+       case 10:
+         pvar->pslot = (debug_type *) xmalloc (sizeof *pvar->pslot);
+         *pvar->pslot = type;
+         type = debug_make_indirect_type (dhandle, pvar->pslot,
+                                          (const char *) NULL);
+         pvar->type = type;
+         break;
+       }
+    }
+
   switch (atn_code)
     {
     default:
@@ -2002,6 +2079,8 @@ parse_ieee_atn (info, pp)
       namcopy = savestring (name, namlen);
       if (type == NULL)
        type = debug_make_void_type (dhandle);
+      if (pvar != NULL)
+       pvar->variable = DEBUG_LOCAL;
       return debug_record_variable (dhandle, namcopy, type, DEBUG_LOCAL, v);
 
     case 2:
@@ -2011,6 +2090,8 @@ parse_ieee_atn (info, pp)
       namcopy = savestring (name, namlen);
       if (type == NULL)
        type = debug_make_void_type (dhandle);
+      if (pvar != NULL)
+       pvar->variable = DEBUG_REGISTER;
       return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER,
                                    ieee_regno_to_genreg (info->abfd, v));
 
@@ -2025,6 +2106,13 @@ parse_ieee_atn (info, pp)
        blocktype = 0;
       else
        blocktype = info->blockstack.bsp[-1].kind;
+      if (pvar != NULL)
+       {
+         if (blocktype == 4 || blocktype == 6)
+           pvar->variable = DEBUG_LOCAL_STATIC;
+         else
+           pvar->variable = DEBUG_STATIC;
+       }
       return debug_record_variable (dhandle, namcopy, type,
                                    (blocktype == 4 || blocktype == 6
                                     ? DEBUG_LOCAL_STATIC
@@ -2067,6 +2155,8 @@ parse_ieee_atn (info, pp)
       namcopy = savestring (name, namlen);
       if (type == NULL)
        type = debug_make_void_type (dhandle);
+      if (pvar != NULL)
+       pvar->variable = DEBUG_GLOBAL;
       return debug_record_variable (dhandle, namcopy, type, DEBUG_GLOBAL, v);
 
     case 9:
@@ -2089,6 +2179,8 @@ parse_ieee_atn (info, pp)
       namcopy = savestring (name, namlen);
       if (type == NULL)
        type = debug_make_void_type (dhandle);
+      if (pvar != NULL)
+       pvar->variable = DEBUG_REGISTER;
       return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, v);
 
     case 11:
@@ -2271,52 +2363,8 @@ ieee_read_cxx_misc (info, pp, count)
       break;
 
     case 'B':
-      {
-       const char *fnname, *strval;
-       unsigned long fnlen, strvallen;
-       bfd_vma count, type, val;
-
-       /* Specify default argument values.  We have no way to store
-           these, so we just ignore them.  FIXME.  */
-
-       /* Giving the function name before the argument count is an
-           addendum to the spec.  */
-       if (! ieee_require_atn65 (info, pp, &fnname, &fnlen)
-           || ! ieee_require_asn (info, pp, &count)
-           || ! ieee_require_asn (info, pp, &type))
-         return false;
-
-       switch (type)
-         {
-         case 0:
-         case 4:
-           break;
-
-         case 1:
-         case 2:
-           if (! ieee_require_asn (info, pp, &val))
-             return false;
-           break;
-
-         case 3:
-         case 7:
-           if (! ieee_require_atn65 (info, pp, &strval, &strvallen))
-             return false;
-           break;
-
-         default:
-           ieee_error (info, start, "unrecognized C++ B type");
-           return false;
-         }
-
-       while (count-- > 0)
-         {
-           bfd_vma pos;
-
-           if (! ieee_require_asn (info, pp, &pos))
-             return false;
-         }
-      }
+      if (! ieee_read_cxx_defaults (info, pp, count))
+       return false;
       break;
 
     case 'z':
@@ -2338,31 +2386,8 @@ ieee_read_cxx_misc (info, pp, count)
       break;
 
     case 'R':
-      {
-       bfd_vma flags;
-       const char *class, *name;
-       unsigned long classlen, namlen;
-
-       /* Indicates that an object actually has reference type.  */
-
-       if (! ieee_require_asn (info, pp, &flags))
-         return false;
-
-       /* Giving the class name before the member name is in an
-           addendum to the spec.  */
-       if (flags == 3)
-         {
-           if (! ieee_require_atn65 (info, pp, &class, &classlen))
-             return false;
-         }
-
-       if (! ieee_require_atn65 (info, pp, &name, &namlen))
-         return false;
-
-       /* FIXME: Now we are supposed to track down the variable or
-           function or class member and convert the type into a
-           reference type.  */
-      }
+      if (! ieee_read_reference (info, pp))
+       return false;
       break;
     }
 
@@ -2603,13 +2628,17 @@ ieee_read_cxx_class (info, pp, count)
              }
            else
              {
+               unsigned int findx;
+
                if (structfields == NULL)
                  {
                    ieee_error (info, start, "C++ object has no fields");
                    return false;
                  }
 
-               for (pf = structfields; *pf != DEBUG_FIELD_NULL; pf++)
+               for (pf = structfields, findx = 0;
+                    *pf != DEBUG_FIELD_NULL;
+                    pf++, findx++)
                  {
                    const char *fname;
 
@@ -2629,6 +2658,35 @@ ieee_read_cxx_class (info, pp, count)
                  }
 
                ftype = debug_get_field_type (dhandle, *pf);
+
+               if (debug_get_type_kind (dhandle, ftype) == DEBUG_KIND_POINTER)
+                 {
+                   /* We might need to convert this field into a
+                       reference type later on, so make it an indirect
+                       type.  */
+                   if (it->fslots == NULL)
+                     {
+                       unsigned int fcnt;
+                       const debug_field *pfcnt;
+
+                       fcnt = 0;
+                       for (pfcnt = structfields;
+                            *pfcnt != DEBUG_FIELD_NULL;
+                            pfcnt++)
+                         ++fcnt;
+                       it->fslots = ((debug_type *)
+                                     xmalloc (fcnt * sizeof *it->fslots));
+                       memset (it->fslots, 0,
+                               fcnt * sizeof *it->fslots);
+                     }
+
+                   if (ftype == DEBUG_TYPE_NULL)
+                     return false;
+                   it->fslots[findx] = ftype;
+                   ftype = debug_make_indirect_type (dhandle,
+                                                     it->fslots + findx,
+                                                     (const char *) NULL);
+                 }
              }
            if (ftype == DEBUG_TYPE_NULL)
              return false;
@@ -2699,7 +2757,7 @@ ieee_read_cxx_class (info, pp, count)
            bfd_vma flags, virtindex, control;
            const char *name, *mangled;
            unsigned long namlen, mangledlen;
-           struct ieee_function *func;
+           struct ieee_var *pv, *pvend;
            debug_type type;
            enum debug_visibility visibility;
            boolean constp, volatilep;
@@ -2730,15 +2788,15 @@ ieee_read_cxx_class (info, pp, count)
            if ((flags & CXXFLAGS_FRIEND) != 0)
              break;
 
-           /* We should already have seen debugging information for
-               the function itself, which will include type
-               information.  */
-           for (func = info->functions; func != NULL; func = func->next)
-             if (func->name[0] == mangled[0]
-                 && strncmp (func->name, mangled, mangledlen)
-                 && strlen (func->name) == mangledlen)
+           /* We should already have seen a type for the function.  */
+           pv = info->vars.vars;
+           pvend = pv + info->vars.alloc;
+           for (; pv < pvend; pv++)
+             if (pv->namlen == mangledlen
+                 && strncmp (pv->name, mangled, mangledlen) == 0)
                break;
-           if (func == NULL)
+
+           if (pv >= pvend)
              {
                /* We won't have type information for this function if
                   it is not included in this file.  We don't try to
@@ -2756,7 +2814,7 @@ ieee_read_cxx_class (info, pp, count)
                const debug_type *arg_types;
                boolean varargs;
 
-               if (debug_get_type_kind (dhandle, func->type)
+               if (debug_get_type_kind (dhandle, pv->type)
                    != DEBUG_KIND_FUNCTION)
                  {
                    ieee_error (info, start,
@@ -2764,8 +2822,8 @@ ieee_read_cxx_class (info, pp, count)
                    return false;
                  }
 
-               return_type = debug_get_return_type (dhandle, func->type);
-               arg_types = debug_get_parameter_types (dhandle, func->type,
+               return_type = debug_get_return_type (dhandle, pv->type);
+               arg_types = debug_get_parameter_types (dhandle, pv->type,
                                                       &varargs);
                if (return_type == DEBUG_TYPE_NULL || arg_types == NULL)
                  {
@@ -2980,6 +3038,7 @@ ieee_read_cxx_class (info, pp, count)
          if (dmethods[i] == DEBUG_METHOD_NULL)
            return false;
        }
+      dmethods[i] = DEBUG_METHOD_NULL;
       free (methods);
     }
 
@@ -2998,6 +3057,274 @@ ieee_read_cxx_class (info, pp, count)
   return true;
 }
 
+/* Read C++ default argument value and reference type information.  */
+
+static boolean
+ieee_read_cxx_defaults (info, pp, count)
+     struct ieee_info *info;
+     const bfd_byte **pp;
+     unsigned long count;
+{
+  const bfd_byte *start;
+  const char *fnname;
+  unsigned long fnlen;
+  bfd_vma defcount;
+
+  start = *pp;
+
+  /* Giving the function name before the argument count is an addendum
+     to the spec.  The function name is demangled, though, so this
+     record must always refer to the current function.  */
+
+  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");
+      return false;
+    }
+
+  if (! ieee_require_atn65 (info, pp, &fnname, &fnlen)
+      || ! ieee_require_asn (info, pp, &defcount))
+    return false;
+  count -= 2;
+
+  while (defcount-- > 0)
+    {
+      bfd_vma type, val;
+      const char *strval;
+      unsigned long strvallen;
+
+      if (! ieee_require_asn (info, pp, &type))
+       return false;
+      --count;
+
+      switch (type)
+       {
+       case 0:
+       case 4:
+         break;
+
+       case 1:
+       case 2:
+         if (! ieee_require_asn (info, pp, &val))
+           return false;
+         --count;
+         break;
+
+       case 3:
+       case 7:
+         if (! ieee_require_atn65 (info, pp, &strval, &strvallen))
+           return false;
+         --count;
+         break;
+
+       default:
+         ieee_error (info, start, "unrecognized C++ default type");
+         return false;
+       }
+
+      /* We have no way to record the default argument values, so we
+         just ignore them.  FIXME.  */
+    }
+
+  /* Any remaining arguments are indices of parameters that are really
+     reference type.  */
+  if (count > 0)
+    {
+      PTR dhandle;
+      debug_type *arg_slots;
+
+      dhandle = info->dhandle;
+      arg_slots = info->types.types[info->blockstack.bsp[-1].fnindx].arg_slots;
+      while (count-- > 0)
+       {
+         bfd_vma indx;
+         debug_type target;
+
+         if (! ieee_require_asn (info, pp, &indx))
+           return false;
+         /* The index is 1 based.  */
+         --indx;
+         if (arg_slots == NULL
+             || arg_slots[indx] == DEBUG_TYPE_NULL
+             || (debug_get_type_kind (dhandle, arg_slots[indx])
+                 != DEBUG_KIND_POINTER))
+           {
+             ieee_error (info, start, "reference parameter is not a pointer");
+             return false;
+           }
+
+         target = debug_get_target_type (dhandle, arg_slots[indx]);
+         arg_slots[indx] = debug_make_reference_type (dhandle, target);
+         if (arg_slots[indx] == DEBUG_TYPE_NULL)
+           return false;
+       }
+    }
+
+  return true;
+}
+
+/* Read a C++ reference definition.  */
+
+static boolean
+ieee_read_reference (info, pp)
+     struct ieee_info *info;
+     const bfd_byte **pp;
+{
+  const bfd_byte *start;
+  bfd_vma flags;
+  const char *class, *name;
+  unsigned long classlen, namlen;
+  debug_type *pslot;
+  debug_type target;
+
+  start = *pp;
+
+  if (! ieee_require_asn (info, pp, &flags))
+    return false;
+
+  /* Giving the class name before the member name is in an addendum to
+     the spec.  */
+  if (flags == 3)
+    {
+      if (! ieee_require_atn65 (info, pp, &class, &classlen))
+       return false;
+    }
+
+  if (! ieee_require_atn65 (info, pp, &name, &namlen))
+    return false;
+
+  pslot = NULL;
+  if (flags != 3)
+    {
+      int i;
+      struct ieee_var *pv = NULL;
+
+      /* 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--)
+       {
+         boolean found;
+
+         pv = info->vars.vars + i;
+
+         if (pv->pslot == NULL
+             || pv->namlen != namlen
+             || strncmp (pv->name, name, namlen) != 0)
+           continue;
+
+         found = false;
+         switch (flags)
+           {
+           default:
+             ieee_error (info, start,
+                         "unrecognized C++ reference type");
+             return false;
+
+           case 0:
+             /* Global variable or function.  */
+             if (pv->variable == DEBUG_GLOBAL)
+               found = true;
+             else if (pv->type != DEBUG_TYPE_NULL
+                      && (debug_get_type_kind (info->dhandle, pv->type)
+                          == DEBUG_KIND_FUNCTION))
+               found = true;
+             break;
+
+           case 1:
+             /* Global static variable or function.  */
+             if (pv->variable == DEBUG_STATIC)
+               found = true;
+             else if (pv->type != DEBUG_TYPE_NULL
+                      && (debug_get_type_kind (info->dhandle, pv->type)
+                          == DEBUG_KIND_FUNCTION))
+               found = true;
+             break;
+
+           case 2:
+             /* Local variable.  */
+             if (pv->variable == DEBUG_LOCAL_STATIC
+                 || pv->variable == DEBUG_LOCAL
+                 || pv->variable == DEBUG_REGISTER)
+               found = true;
+             break;
+           }
+
+         if (found)
+           break;
+       }
+
+      if (i >= 0)
+       pslot = pv->pslot;
+    }
+  else
+    {
+      struct ieee_tag *it;
+
+      for (it = info->tags; it != NULL; it = it->next)
+       {
+         if (it->name[0] == class[0]
+             && strncmp (it->name, class, classlen) == 0
+             && strlen (it->name) == classlen)
+           {
+             if (it->fslots != NULL)
+               {
+                 const debug_field *pf;
+                 unsigned int findx;
+
+                 pf = debug_get_fields (info->dhandle, it->type);
+                 if (pf == NULL)
+                   {
+                     ieee_error (info, start,
+                                 "C++ reference in class with no fields");
+                     return false;
+                   }
+
+                 for (findx = 0; *pf != DEBUG_FIELD_NULL; pf++, findx++)
+                   {
+                     const char *fname;
+
+                     fname = debug_get_field_name (info->dhandle, *pf);
+                     if (fname == NULL)
+                       return false;
+                     if (strncmp (fname, name, namlen) == 0
+                         && strlen (fname) == namlen)
+                       {
+                         pslot = it->fslots + findx;
+                         break;
+                       }
+                   }
+               }
+
+             break;
+           }
+       }
+    }
+
+  if (pslot == NULL)
+    {
+      ieee_error (info, start, "C++ reference not found");
+      return false;
+    }
+
+  /* We allocated the type of the object as an indirect type pointing
+     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");
+      return false;
+    }
+
+  target = debug_get_target_type (info->dhandle, *pslot);
+  *pslot = debug_make_reference_type (info->dhandle, target);
+  if (*pslot == DEBUG_TYPE_NULL)
+    return false;
+
+  return true;
+}
+
 /* Require an ASN record.  */
 
 static boolean