]> Git Repo - binutils.git/blobdiff - gdb/stabsread.c
* core.c (dis_asm_read_memory): drop fourth arg which conflicts with
[binutils.git] / gdb / stabsread.c
index d6da541b4b4eb6774743a15e60d31a60b832c6a8..796fac522f1101268bf45c298fa8fc3195f46b10 100644 (file)
@@ -1,5 +1,5 @@
 /* Support routines for decoding "stabs" debugging information format.
-   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992
+   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993
              Free Software Foundation, Inc.
 
 This file is part of GDB.
@@ -29,16 +29,39 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "obstack.h"
 #include "symtab.h"
 #include "gdbtypes.h"
-#include "symfile.h"           /* Needed for "struct complaint" */
+#include "symfile.h"
 #include "objfiles.h"
 #include "aout/stab_gnu.h"     /* We always use GNU stabs, not native */
 #include "buildsym.h"
+#include "complaints.h"
+#include "demangle.h"
 
 /* Ask stabsread.h to define the vars it normally declares `extern'.  */
 #define        EXTERN  /**/
 #include "stabsread.h"         /* Our own declarations */
 #undef EXTERN
 
+/* The routines that read and process a complete stabs for a C struct or 
+   C++ class pass lists of data member fields and lists of member function
+   fields in an instance of a field_info structure, as defined below.
+   This is part of some reorganization of low level C++ support and is
+   expected to eventually go away... (FIXME) */
+
+struct field_info
+{
+  struct nextfield
+    {
+      struct nextfield *next;
+      int visibility;
+      struct field field;
+    } *list;
+  struct next_fnfieldlist
+    {
+      struct next_fnfieldlist *next;
+      struct fn_fieldlist fn_fieldlist;
+    } *fnlist;
+};
+
 static struct type *
 dbx_alloc_type PARAMS ((int [2], struct objfile *));
 
@@ -64,6 +87,32 @@ read_sun_floating_type PARAMS ((char **, int [2], struct objfile *));
 static struct type *
 read_enum_type PARAMS ((char **, struct type *, struct objfile *));
 
+static struct type *
+rs6000_builtin_type PARAMS ((int));
+
+static int
+read_member_functions PARAMS ((struct field_info *, char **, struct type *,
+                              struct objfile *));
+
+static int
+read_struct_fields PARAMS ((struct field_info *, char **, struct type *,
+                           struct objfile *));
+
+static int
+read_baseclasses PARAMS ((struct field_info *, char **, struct type *,
+                         struct objfile *));
+
+static int
+read_tilde_fields PARAMS ((struct field_info *, char **, struct type *,
+                          struct objfile *));
+
+static int
+attach_fn_fields_to_type PARAMS ((struct field_info *, struct type *));
+
+static int
+attach_fields_to_type PARAMS ((struct field_info *, struct type *,
+                              struct objfile *));
+
 static struct type *
 read_struct_type PARAMS ((char **, struct type *, struct objfile *));
 
@@ -73,6 +122,10 @@ read_array_type PARAMS ((char **, struct type *, struct objfile *));
 static struct type **
 read_args PARAMS ((char **, int, struct objfile *));
 
+static void
+read_cpp_abbrev PARAMS ((struct field_info *, char **, struct type *,
+                        struct objfile *));
+
 static const char vptr_name[] = { '_','v','p','t','r',CPLUS_MARKER,'\0' };
 static const char vb_name[] =   { '_','v','b',CPLUS_MARKER,'\0' };
 
@@ -127,12 +180,30 @@ struct complaint range_type_base_complaint =
 struct complaint reg_value_complaint =
   {"register number too large in symbol %s", 0, 0};
 
+struct complaint vtbl_notfound_complaint =
+  {"virtual function table pointer not found when defining class `%s'", 0, 0};
+
+struct complaint unrecognized_cplus_name_complaint =
+  {"Unknown C++ symbol name `%s'", 0, 0};
+
+struct complaint rs6000_builtin_complaint =
+  {"Unknown builtin type %d", 0, 0};
+
+struct complaint stabs_general_complaint =
+  {"%s", 0, 0};
+
 /* Make a list of forward references which haven't been defined.  */
 
 static struct type **undef_types;
 static int undef_types_allocated;
 static int undef_types_length;
 
+/* Check for and handle cretinous stabs symbol name continuation!  */
+#define STABS_CONTINUE(pp)                             \
+  do {                                                 \
+    if (**(pp) == '\\') *(pp) = next_symbol_text ();   \
+  } while (0)
+
 \f
 int
 hashname (name)
@@ -190,6 +261,19 @@ dbx_lookup_type (typenums)
 
   if (filenum == 0)
     {
+      if (index < 0)
+       {
+         /* Caller wants address of address of type.  We think
+            that negative (rs6k builtin) types will never appear as
+            "lvalues", (nor should they), so we stuff the real type
+            pointer into a temp, and return its address.  If referenced,
+            this will do the right thing.  */
+         static struct type *temp_type;
+
+         temp_type = rs6000_builtin_type(index);
+         return &temp_type;
+       }
+
       /* Type is defined outside of header files.
         Find it in this object file's type vector.  */
       if (index >= type_vector_length)
@@ -371,7 +455,7 @@ define_symbol (valu, string, desc, type, objfile)
 
   /* We would like to eliminate nameless symbols, but keep their types.
      E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer
-     to type 2, but, should not creat a symbol to address that type. Since
+     to type 2, but, should not create a symbol to address that type. Since
      the symbol will be nameless, there is no way any user can refer to it. */
 
   int nameless;
@@ -385,11 +469,12 @@ define_symbol (valu, string, desc, type, objfile)
     return 0;
 
   /* If a nameless stab entry, all we need is the type, not the symbol.
-     e.g. ":t10=*2" */
-  nameless = (p == string);
+     e.g. ":t10=*2" or a nameless enum like " :T16=ered:0,green:1,blue:2,;" */
+  nameless = (p == string || ((string[0] == ' ') && (string[1] == ':')));
 
   sym = (struct symbol *) 
     obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+  memset (sym, 0, sizeof (struct symbol));
 
   if (processing_gcc_compilation)
     {
@@ -426,15 +511,19 @@ define_symbol (valu, string, desc, type, objfile)
            goto normal;
 
          default:
-           abort ();
+           complain (unrecognized_cplus_name_complaint, string);
+           goto normal;                /* Do *something* with it */
        }
     }
   else
     {
     normal:
+      SYMBOL_LANGUAGE (sym) = current_subfile -> language;
       SYMBOL_NAME (sym)        = (char *)
        obstack_alloc (&objfile -> symbol_obstack, ((p - string) + 1));
       /* Open-coded bcopy--saves function call time.  */
+      /* FIXME:  Does it really?  Try replacing with simple strcpy and
+        try it on an executable with a large symbol table. */
       {
        register char *p1 = string;
        register char *p2 = SYMBOL_NAME (sym);
@@ -444,28 +533,21 @@ define_symbol (valu, string, desc, type, objfile)
          }
        *p2++ = '\0';
       }
+
+      /* If this symbol is from a C++ compilation, then attempt to cache the
+        demangled form for future reference.  This is a typical time versus
+        space tradeoff, that was decided in favor of time because it sped up
+        C++ symbol lookups by a factor of about 20. */
+
+      SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack);
     }
   p++;
+
   /* Determine the type of name being defined.  */
   /* The Acorn RISC machine's compiler can put out locals that don't
      start with "234=" or "(3,4)=", so assume anything other than the
      deftypes we know how to handle is a local.  */
-  /* (Peter Watkins @ Computervision)
-     Handle Sun-style local fortran array types 'ar...' . 
-     ([email protected]) -- this strchr() handles them properly?
-     ([email protected]) -- 'C' is for catch.  */
-
-#ifdef IBM6000_TARGET
-
-  /* 'R' is for register parameters. */
-
   if (!strchr ("cfFGpPrStTvVXCR", *p))
-
-#else
-
-  if (!strchr ("cfFGpPrStTvVXC", *p))
-
-#endif
     deftype = 'l';
   else
     deftype = *p++;
@@ -490,8 +572,7 @@ define_symbol (valu, string, desc, type, objfile)
            SYMBOL_TYPE (sym) = lookup_fundamental_type (objfile,
                                                         FT_DBL_PREC_FLOAT);
            dbl_valu = (char *)
-             obstack_alloc (&objfile -> type_obstack,
-                            sizeof (double));
+             obstack_alloc (&objfile -> symbol_obstack, sizeof (double));
            memcpy (dbl_valu, &d, sizeof (double));
            SWAP_TARGET_AND_HOST (dbl_valu, sizeof (double));
            SYMBOL_VALUE_BYTES (sym) = dbl_valu;
@@ -543,12 +624,6 @@ define_symbol (valu, string, desc, type, objfile)
       SYMBOL_TYPE (sym)
        = lookup_pointer_type (lookup_function_type (read_type (&p, objfile)));
     }
-
-#ifdef IBM6000_TARGET
-  else if (deftype == 'R')
-      SYMBOL_TYPE (sym) = read_type (&p, objfile);
-#endif
-
   else
     {
       /* The symbol class letter is followed by a type (typically the
@@ -558,7 +633,7 @@ define_symbol (valu, string, desc, type, objfile)
 
       if (synonym)
        {
-         p += 1;
+         p++;
          type_synonym_name = obsavestring (SYMBOL_NAME (sym),
                                            strlen (SYMBOL_NAME (sym)),
                                            &objfile -> symbol_obstack);
@@ -602,9 +677,7 @@ define_symbol (valu, string, desc, type, objfile)
 #if 0
          /* This code doesn't work -- it needs to realloc and can't.  */
          /* Attempt to set up to record a function prototype... */
-         struct type *new = (struct type *)
-           obstack_alloc (&objfile -> type_obstack,
-                          sizeof (struct type));
+         struct type *new = alloc_type (objfile);
 
          /* Generate a template for the type of this function.  The 
             types of the arguments will be added as we read the symbol 
@@ -749,23 +822,21 @@ define_symbol (valu, string, desc, type, objfile)
       SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
       if (SYMBOL_VALUE (sym) >= NUM_REGS)
        {
-         complain (&reg_value_complaint, SYMBOL_NAME (sym));
+         complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
          SYMBOL_VALUE (sym) = SP_REGNUM;  /* Known safe, though useless */
        }
       SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
       add_symbol_to_list (sym, &local_symbols);
       break;
 
-#ifdef IBM6000_TARGET
     case 'R':
-#endif
     case 'r':
       /* Register variable (either global or local).  */
       SYMBOL_CLASS (sym) = LOC_REGISTER;
       SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
       if (SYMBOL_VALUE (sym) >= NUM_REGS)
        {
-         complain (&reg_value_complaint, SYMBOL_NAME (sym));
+         complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
          SYMBOL_VALUE (sym) = SP_REGNUM;  /* Known safe, though useless */
        }
       SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
@@ -830,12 +901,10 @@ define_symbol (valu, string, desc, type, objfile)
 
       if (synonym)
        {
+         /* Clone the sym and then modify it. */
          register struct symbol *typedef_sym = (struct symbol *)
-           obstack_alloc (&objfile -> type_obstack,
-                          sizeof (struct symbol));
-         SYMBOL_NAME (typedef_sym) = SYMBOL_NAME (sym);
-         SYMBOL_TYPE (typedef_sym) = SYMBOL_TYPE (sym);
-
+           obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+         *typedef_sym = *sym;
          SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF;
          SYMBOL_VALUE (typedef_sym) = valu;
          SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE;
@@ -910,20 +979,26 @@ struct type *
 error_type (pp)
      char **pp;
 {
-  complain (&error_type_complaint, 0);
+  complain (&error_type_complaint);
   while (1)
     {
       /* Skip to end of symbol.  */
       while (**pp != '\0')
-       (*pp)++;
+       {
+         (*pp)++;
+       }
 
       /* Check for and handle cretinous dbx symbol name continuation!  */
       if ((*pp)[-1] == '\\')
-       *pp = next_symbol_text ();
+       {
+         *pp = next_symbol_text ();
+       }
       else
-       break;
+       {
+         break;
+       }
     }
-  return builtin_type_error;
+  return (builtin_type_error);
 }
 
 \f
@@ -944,6 +1019,7 @@ read_type (pp, objfile)
   struct type *type1;
   int typenums[2];
   int xtypenums[2];
+  char type_descriptor;
 
   /* Read type number if present.  The type number may be omitted.
      for instance in a two-dimensional array declared with type
@@ -982,10 +1058,11 @@ read_type (pp, objfile)
       /* 'typenums=' not present, type is anonymous.  Read and return
         the definition, but don't put it in the type vector.  */
       typenums[0] = typenums[1] = -1;
-      *pp += 1;
+      (*pp)++;
     }
 
-  switch ((*pp)[-1])
+  type_descriptor = (*pp)[-1];
+  switch (type_descriptor)
     {
     case 'x':
       {
@@ -1031,7 +1108,7 @@ read_type (pp, objfile)
        
          /* Copy the prefix.  */
          from = prefix;
-         while (*to++ = *from++)
+         while ((*to++ = *from++) != '\0')
            ;
          to--; 
        
@@ -1079,7 +1156,7 @@ read_type (pp, objfile)
              if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
                  && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
                  && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
-                 && !strcmp (SYMBOL_NAME (sym), type_name_only))
+                 && STREQ (SYMBOL_NAME (sym), type_name_only))
                {
                  obstack_free (&objfile -> type_obstack, type_name);
                  type = SYMBOL_TYPE (sym);
@@ -1103,10 +1180,6 @@ read_type (pp, objfile)
       }
 
     case '-':                          /* RS/6000 built-in type */
-      (*pp)--;
-      type = builtin_type (pp);                /* (in xcoffread.c) */
-      goto after_digits;
-
     case '0':
     case '1':
     case '2':
@@ -1121,9 +1194,6 @@ read_type (pp, objfile)
       (*pp)--;
       read_type_number (pp, xtypenums);
       type = *dbx_lookup_type (xtypenums);
-      /* fall through */
-
-    after_digits:
       if (type == 0)
        type = lookup_fundamental_type (objfile, FT_VOID);
       if (typenums[0] != -1)
@@ -1185,10 +1255,10 @@ read_type (pp, objfile)
          /* We'll get the parameter types from the name.  */
          struct type *return_type;
 
-         *pp += 1;
+         (*pp)++;
          return_type = read_type (pp, objfile);
          if (*(*pp)++ != ';')
-           complain (&invalid_member_complaint, (char *) symnum);
+           complain (&invalid_member_complaint, symnum);
          type = allocate_stub_method (return_type);
          if (typenums[0] != -1)
            *dbx_lookup_type (typenums) = type;
@@ -1235,20 +1305,23 @@ read_type (pp, objfile)
       break;
 
     case 's':                          /* Struct type */
-      type = dbx_alloc_type (typenums, objfile);
-      if (!TYPE_NAME (type))
-        TYPE_NAME (type) = type_synonym_name;
-      type_synonym_name = 0;
-      type = read_struct_type (pp, type, objfile);
-      break;
-
     case 'u':                          /* Union type */
       type = dbx_alloc_type (typenums, objfile);
       if (!TYPE_NAME (type))
-       TYPE_NAME (type) = type_synonym_name;
-      type_synonym_name = 0;
+       {
+         TYPE_NAME (type) = type_synonym_name;
+       }
+      type_synonym_name = NULL;
+      switch (type_descriptor)
+       {
+         case 's':
+           TYPE_CODE (type) = TYPE_CODE_STRUCT;
+           break;
+         case 'u':
+           TYPE_CODE (type) = TYPE_CODE_UNION;
+           break;
+       }
       type = read_struct_type (pp, type, objfile);
-      TYPE_CODE (type) = TYPE_CODE_UNION;
       break;
 
     case 'a':                          /* Array type */
@@ -1272,738 +1345,1041 @@ read_type (pp, objfile)
   return type;
 }
 \f
+/* RS/6000 xlc/dbx combination uses a set of builtin types, starting from -1.
+   Return the proper type node for a given builtin type number. */
+
+static struct type *
+rs6000_builtin_type (typenum)
+  int typenum;
+{
+  /* default types are defined in dbxstclass.h. */
+  switch (-typenum) {
+  case 1: 
+    return lookup_fundamental_type (current_objfile, FT_INTEGER);
+  case 2: 
+    return lookup_fundamental_type (current_objfile, FT_CHAR);
+  case 3: 
+    return lookup_fundamental_type (current_objfile, FT_SHORT);
+  case 4: 
+    return lookup_fundamental_type (current_objfile, FT_LONG);
+  case 5: 
+    return lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+  case 6: 
+    return lookup_fundamental_type (current_objfile, FT_SIGNED_CHAR);
+  case 7: 
+    return lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
+  case 8: 
+    return lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+  case 9: 
+    return lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+  case 10: 
+    return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
+  case 11: 
+    return lookup_fundamental_type (current_objfile, FT_VOID);
+  case 12: 
+    return lookup_fundamental_type (current_objfile, FT_FLOAT);
+  case 13: 
+    return lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
+  case 14: 
+    return lookup_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT);
+  case 15: 
+    /* requires a builtin `integer' */
+    return lookup_fundamental_type (current_objfile, FT_INTEGER);
+  case 16: 
+    return lookup_fundamental_type (current_objfile, FT_BOOLEAN);
+  case 17: 
+    /* requires builtin `short real' */
+    return lookup_fundamental_type (current_objfile, FT_FLOAT);
+  case 18: 
+    /* requires builtin `real' */
+    return lookup_fundamental_type (current_objfile, FT_FLOAT);
+  default:
+    complain (rs6000_builtin_complaint, typenum);
+    return NULL;
+  }
+}
+\f
 /* This page contains subroutines of read_type.  */
 
-/* Read the description of a structure (or union type)
-   and return an object describing the type.  */
+#define VISIBILITY_PRIVATE     '0'     /* Stabs character for private field */
+#define VISIBILITY_PROTECTED   '1'     /* Stabs character for protected fld */
+#define VISIBILITY_PUBLIC      '2'     /* Stabs character for public field */
 
-static struct type *
-read_struct_type (pp, type, objfile)
+/* Read member function stabs info for C++ classes.  The form of each member
+   function data is:
+
+       NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ;
+
+   An example with two member functions is:
+
+       afunc1::20=##15;:i;2A.;afunc2::20:i;2A.;
+
+   For the case of overloaded operators, the format is op$::*.funcs, where
+   $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
+   name (such as `+=') and `.' marks the end of the operator name.  */
+
+static int
+read_member_functions (fip, pp, type, objfile)
+     struct field_info *fip;
      char **pp;
-     register struct type *type;
+     struct type *type;
      struct objfile *objfile;
 {
-  /* Total number of methods defined in this class.
-     If the class defines two `f' methods, and one `g' method,
-     then this will have the value 3.  */
+  int nfn_fields = 0;
+  int length = 0;
+  /* Total number of member functions defined in this class.  If the class
+     defines two `f' functions, and one `g' function, then this will have
+     the value 3.  */
   int total_length = 0;
-
-  struct nextfield
-    {
-      struct nextfield *next;
-      int visibility;                  /* 0=public, 1=protected, 2=public */
-      struct field field;
-    };
-
+  int i;
   struct next_fnfield
     {
       struct next_fnfield *next;
       struct fn_field fn_field;
-    };
-
-  struct next_fnfieldlist
-    {
-      struct next_fnfieldlist *next;
-      struct fn_fieldlist fn_fieldlist;
-    };
-
-  register struct nextfield *list = 0;
-  struct nextfield *new;
+    } *sublist;
+  struct type *look_ahead_type;
+  struct next_fnfieldlist *new_fnlist;
+  struct next_fnfield *new_sublist;
+  char *main_fn_name;
   register char *p;
-  int nfields = 0;
-  int non_public_fields = 0;
-  register int n;
-
-  register struct next_fnfieldlist *mainlist = 0;
-  int nfn_fields = 0;
-
-  TYPE_CODE (type) = TYPE_CODE_STRUCT;
-  INIT_CPLUS_SPECIFIC(type);
-  TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
-
-  /* First comes the total size in bytes.  */
-
-  TYPE_LENGTH (type) = read_number (pp, 0);
+      
+  /* Process each list until we find something that is not a member function
+     or find the end of the functions. */
 
-  /* C++: Now, if the class is a derived class, then the next character
-     will be a '!', followed by the number of base classes derived from.
-     Each element in the list contains visibility information,
-     the offset of this base class in the derived structure,
-     and then the base type. */
-  if (**pp == '!')
+  while (**pp != ';')
     {
-      int i, n_baseclasses, offset;
-      struct type *baseclass;
-      int via_public;
-
-      /* Nonzero if it is a virtual baseclass, i.e.,
-
-        struct A{};
-        struct B{};
-        struct C : public B, public virtual A {};
-
-        B is a baseclass of C; A is a virtual baseclass for C.  This is a C++
-        2.0 language feature.  */
-      int via_virtual;
-
-      *pp += 1;
-
-      ALLOCATE_CPLUS_STRUCT_TYPE(type);
-
-      n_baseclasses = read_number (pp, ',');
-      TYPE_FIELD_VIRTUAL_BITS (type) =
-       (B_TYPE *) obstack_alloc (&objfile -> type_obstack,
-                                 B_BYTES (n_baseclasses));
-      B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), n_baseclasses);
+      /* We should be positioned at the start of the function name.
+        Scan forward to find the first ':' and if it is not the
+        first of a "::" delimiter, then this is not a member function. */
+      p = *pp;
+      while (*p != ':')
+       {
+         p++;
+       }
+      if (p[1] != ':')
+       {
+         break;
+       }
 
-      for (i = 0; i < n_baseclasses; i++)
+      sublist = NULL;
+      look_ahead_type = NULL;
+      length = 0;
+      
+      new_fnlist = (struct next_fnfieldlist *)
+       xmalloc (sizeof (struct next_fnfieldlist));
+      make_cleanup (free, new_fnlist);
+      memset (new_fnlist, 0, sizeof (struct next_fnfieldlist));
+      
+      if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == CPLUS_MARKER)
        {
-         if (**pp == '\\')
-           *pp = next_symbol_text ();
+         /* This is a completely wierd case.  In order to stuff in the
+            names that might contain colons (the usual name delimiter),
+            Mike Tiemann defined a different name format which is
+            signalled if the identifier is "op$".  In that case, the
+            format is "op$::XXXX." where XXXX is the name.  This is
+            used for names like "+" or "=".  YUUUUUUUK!  FIXME!  */
+         /* This lets the user type "break operator+".
+            We could just put in "+" as the name, but that wouldn't
+            work for "*".  */
+         static char opname[32] = {'o', 'p', CPLUS_MARKER};
+         char *o = opname + 3;
+         
+         /* Skip past '::'.  */
+         *pp = p + 2;
 
-         switch (**pp)
+         STABS_CONTINUE (pp);
+         p = *pp;
+         while (*p != '.')
            {
-           case '0':
-             via_virtual = 0;
-             break;
-           case '1':
-             via_virtual = 1;
-             break;
-           default:
-             /* Bad visibility format.  */
-             return error_type (pp);
+             *o++ = *p++;
+           }
+         main_fn_name = savestring (opname, o - opname);
+         /* Skip past '.'  */
+         *pp = p + 1;
+       }
+      else
+       {
+         main_fn_name = savestring (*pp, p - *pp);
+         /* Skip past '::'.  */
+         *pp = p + 2;
+       }
+      new_fnlist -> fn_fieldlist.name = main_fn_name;
+      
+      do
+       {
+         new_sublist =
+           (struct next_fnfield *) xmalloc (sizeof (struct next_fnfield));
+         make_cleanup (free, new_sublist);
+         memset (new_sublist, 0, sizeof (struct next_fnfield));
+         
+         /* Check for and handle cretinous dbx symbol name continuation!  */
+         if (look_ahead_type == NULL)
+           {
+             /* Normal case. */
+             STABS_CONTINUE (pp);
+             
+             new_sublist -> fn_field.type = read_type (pp, objfile);
+             if (**pp != ':')
+               {
+                 /* Invalid symtab info for member function.  */
+                 return 0;
+               }
+           }
+         else
+           {
+             /* g++ version 1 kludge */
+             new_sublist -> fn_field.type = look_ahead_type;
+             look_ahead_type = NULL;
+           }
+         
+         (*pp)++;
+         p = *pp;
+         while (*p != ';')
+           {
+             p++;
            }
-         ++*pp;
+         
+         /* If this is just a stub, then we don't have the real name here. */
 
+         if (TYPE_FLAGS (new_sublist -> fn_field.type) & TYPE_FLAG_STUB)
+           {
+             new_sublist -> fn_field.is_stub = 1;
+           }
+         new_sublist -> fn_field.physname = savestring (*pp, p - *pp);
+         *pp = p + 1;
+         
+         /* Set this member function's visibility fields.  */
+         switch (*(*pp)++)
+           {
+             case VISIBILITY_PRIVATE:
+               new_sublist -> fn_field.is_private = 1;
+               break;
+             case VISIBILITY_PROTECTED:
+               new_sublist -> fn_field.is_protected = 1;
+               break;
+           }
+         
+         STABS_CONTINUE (pp);
          switch (**pp)
            {
-           case '0':
-             via_public = 0;
-             non_public_fields++;
-             break;
-           case '2':
-             via_public = 2;
-             break;
-           default:
-             /* Bad visibility format.  */
-             return error_type (pp);
+             case 'A': /* Normal functions. */
+               new_sublist -> fn_field.is_const = 0;
+               new_sublist -> fn_field.is_volatile = 0;
+               (*pp)++;
+               break;
+             case 'B': /* `const' member functions. */
+               new_sublist -> fn_field.is_const = 1;
+               new_sublist -> fn_field.is_volatile = 0;
+               (*pp)++;
+               break;
+             case 'C': /* `volatile' member function. */
+               new_sublist -> fn_field.is_const = 0;
+               new_sublist -> fn_field.is_volatile = 1;
+               (*pp)++;
+               break;
+             case 'D': /* `const volatile' member function. */
+               new_sublist -> fn_field.is_const = 1;
+               new_sublist -> fn_field.is_volatile = 1;
+               (*pp)++;
+               break;
+             case '*': /* File compiled with g++ version 1 -- no info */
+             case '?':
+             case '.':
+               break;
+             default:
+               complain (&const_vol_complaint, **pp);
+               break;
            }
-         if (via_virtual) 
-           SET_TYPE_FIELD_VIRTUAL (type, i);
-         ++*pp;
-
-         /* Offset of the portion of the object corresponding to
-            this baseclass.  Always zero in the absence of
-            multiple inheritance.  */
-         offset = read_number (pp, ',');
-         baseclass = read_type (pp, objfile);
-         *pp += 1;             /* skip trailing ';' */
-
-         /* Make this baseclass visible for structure-printing purposes.  */
-         new = (struct nextfield *) alloca (sizeof (struct nextfield));
-         memset (new, 0, sizeof (struct nextfield));
-         new->next = list;
-         list = new;
-         list->visibility = via_public;
-         list->field.type = baseclass;
-         list->field.name = type_name_no_tag (baseclass);
-         list->field.bitpos = offset;
-         list->field.bitsize = 0;      /* this should be an unpacked field! */
-         nfields++;
+         
+         switch (*(*pp)++)
+           {
+             case '*':
+               /* virtual member function, followed by index.
+                  The sign bit is set to distinguish pointers-to-methods
+                  from virtual function indicies.  Since the array is
+                  in words, the quantity must be shifted left by 1
+                  on 16 bit machine, and by 2 on 32 bit machine, forcing
+                  the sign bit out, and usable as a valid index into
+                  the array.  Remove the sign bit here.  */
+               new_sublist -> fn_field.voffset =
+                 (0x7fffffff & read_number (pp, ';')) + 2;
+             
+               STABS_CONTINUE (pp);
+               if (**pp == ';' || **pp == '\0')
+                 {
+                   /* Must be g++ version 1.  */
+                   new_sublist -> fn_field.fcontext = 0;
+                 }
+               else
+                 {
+                   /* Figure out from whence this virtual function came.
+                      It may belong to virtual function table of
+                      one of its baseclasses.  */
+                   look_ahead_type = read_type (pp, objfile);
+                   if (**pp == ':')
+                     {
+                       /* g++ version 1 overloaded methods. */
+                     }
+                   else
+                     {
+                       new_sublist -> fn_field.fcontext = look_ahead_type;
+                       if (**pp != ';')
+                         {
+                           return 0;
+                         }
+                       else
+                         {
+                           ++*pp;
+                         }
+                       look_ahead_type = NULL;
+                     }
+                 }
+               break;
+             
+             case '?':
+               /* static member function.  */
+               new_sublist -> fn_field.voffset = VOFFSET_STATIC;
+               if (strncmp (new_sublist -> fn_field.physname,
+                            main_fn_name, strlen (main_fn_name)))
+                 {
+                   new_sublist -> fn_field.is_stub = 1;
+                 }
+               break;
+             
+             default:
+               /* error */
+               complain (&member_fn_complaint, (*pp)[-1]);
+               /* Fall through into normal member function.  */
+             
+             case '.':
+               /* normal member function.  */
+               new_sublist -> fn_field.voffset = 0;
+               new_sublist -> fn_field.fcontext = 0;
+               break;
+           }
+         
+         new_sublist -> next = sublist;
+         sublist = new_sublist;
+         length++;
+         STABS_CONTINUE (pp);
        }
-      TYPE_N_BASECLASSES (type) = n_baseclasses;
+      while (**pp != ';' && **pp != '\0');
+      
+      (*pp)++;
+      
+      new_fnlist -> fn_fieldlist.fn_fields = (struct fn_field *)
+       obstack_alloc (&objfile -> type_obstack, 
+                      sizeof (struct fn_field) * length);
+      memset (new_fnlist -> fn_fieldlist.fn_fields, 0,
+             sizeof (struct fn_field) * length);
+      for (i = length; (i--, sublist); sublist = sublist -> next)
+       {
+         new_fnlist -> fn_fieldlist.fn_fields[i] = sublist -> fn_field;
+       }
+      
+      new_fnlist -> fn_fieldlist.length = length;
+      new_fnlist -> next = fip -> fnlist;
+      fip -> fnlist = new_fnlist;
+      nfn_fields++;
+      total_length += length;
+      STABS_CONTINUE (pp);
     }
 
-  /* Now come the fields, as NAME:?TYPENUM,BITPOS,BITSIZE; for each one.
-     At the end, we see a semicolon instead of a field.
+  if (nfn_fields)
+    {
+      ALLOCATE_CPLUS_STRUCT_TYPE (type);
+      TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
+       TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * nfn_fields);
+      memset (TYPE_FN_FIELDLISTS (type), 0,
+             sizeof (struct fn_fieldlist) * nfn_fields);
+      TYPE_NFN_FIELDS (type) = nfn_fields;
+      TYPE_NFN_FIELDS_TOTAL (type) = total_length;
+    }
 
-     In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
-     a static field.
+  return 1;
+}
 
-     The `?' is a placeholder for one of '/2' (public visibility),
-     '/1' (protected visibility), '/0' (private visibility), or nothing
-     (C style symbol table, public visibility).  */
+/* Special GNU C++ name.
+   FIXME:  Still need to properly handle parse error conditions. */
 
-  /* We better set p right now, in case there are no fields at all...    */
-  p = *pp;
+static void
+read_cpp_abbrev (fip, pp, type, objfile)
+     struct field_info *fip;
+     char **pp;
+     struct type *type;
+     struct objfile *objfile;
+{
+  register char *p;
+  const char *prefix;
+  char *name;
+  char cpp_abbrev;
+  struct type *context;
 
-  while (**pp != ';')
+  p = *pp;
+  if (*++p == 'v')
     {
-      /* Check for and handle cretinous dbx symbol name continuation!  */
-      if (**pp == '\\') *pp = next_symbol_text ();
+      name = NULL;
+      cpp_abbrev = *++p;
 
-      /* Get space to record the next field's data.  */
-      new = (struct nextfield *) alloca (sizeof (struct nextfield));
-      memset (new, 0, sizeof (struct nextfield));
-      new->next = list;
-      list = new;
+      *pp = p + 1;
 
-      /* Get the field name.  */
-      p = *pp;
-      if (*p == CPLUS_MARKER)
+      /* At this point, *pp points to something like "22:23=*22...",
+        where the type number before the ':' is the "context" and
+        everything after is a regular type definition.  Lookup the
+        type, find it's name, and construct the field name. */
+
+      context = read_type (pp, objfile);
+
+      switch (cpp_abbrev)
        {
-         /* Special GNU C++ name.  */
-         if (*++p == 'v')
-           {
-             const char *prefix;
-             char *name = 0;
-             struct type *context;
+         case 'f':             /* $vf -- a virtual function table pointer */
+           fip->list->field.name =
+             obconcat (&objfile->type_obstack, vptr_name, "", "");
+           break;
 
-             switch (*++p)
-               {
-               case 'f':
-                 prefix = vptr_name;
-                 break;
-               case 'b':
-                 prefix = vb_name;
-                 break;
-               default:
-                 complain (&invalid_cpp_abbrev_complaint, *pp);
-                 prefix = "INVALID_C++_ABBREV";
-                 break;
-               }
-             *pp = p + 1;
-             context = read_type (pp, objfile);
-             name = type_name_no_tag (context);
-             if (name == 0)
-               {
-                 complain (&invalid_cpp_type_complaint, (char *) symnum);
-                 name = "FOO";
-               }
-             list->field.name = obconcat (&objfile -> type_obstack,
-                                          prefix, name, "");
-             p = ++(*pp);
-             if (p[-1] != ':')
-               complain (&invalid_cpp_abbrev_complaint, *pp);
-             list->field.type = read_type (pp, objfile);
-             (*pp)++;                  /* Skip the comma.  */
-             list->field.bitpos = read_number (pp, ';');
-             /* This field is unpacked.  */
-             list->field.bitsize = 0;
-             list->visibility = 0;     /* private */
-             non_public_fields++;
-           }
-         /* GNU C++ anonymous type.  */
-         else if (*p == '_')
+         case 'b':             /* $vb -- a virtual bsomethingorother */
+           name = type_name_no_tag (context);
+           if (name == NULL)
+             {
+               complain (&invalid_cpp_type_complaint, symnum);
+               name = "FOO";
+             }
+           fip->list->field.name =
+             obconcat (&objfile->type_obstack, vb_name, name, "");
            break;
-         else
-           complain (&invalid_cpp_abbrev_complaint, *pp);
 
-         nfields++;
-         continue;
+         default:
+           complain (&invalid_cpp_abbrev_complaint, *pp);
+           fip->list->field.name =
+             obconcat (&objfile->type_obstack,
+                       "INVALID_CPLUSPLUS_ABBREV", "", "");
+           break;
        }
 
-      while (*p != ':') p++;
-      list->field.name = obsavestring (*pp, p - *pp,
-                                      &objfile -> type_obstack);
-
-      /* C++: Check to see if we have hit the methods yet.  */
-      if (p[1] == ':')
-       break;
-
-      *pp = p + 1;
+      /* At this point, *pp points to the ':'.  Skip it and read the
+        field type. */
 
-      /* This means we have a visibility for a field coming. */
-      if (**pp == '/')
+      p = ++(*pp);
+      if (p[-1] != ':')
        {
-         switch (*++*pp)
-           {
-           case '0':
-             list->visibility = 0;     /* private */
-             non_public_fields++;
-             *pp += 1;
-             break;
-
-           case '1':
-             list->visibility = 1;     /* protected */
-             non_public_fields++;
-             *pp += 1;
-             break;
-
-           case '2':
-             list->visibility = 2;     /* public */
-             *pp += 1;
-             break;
-           }
-       }
-       else /* normal dbx-style format.  */
-       list->visibility = 2;           /* public */
-
-      list->field.type = read_type (pp, objfile);
-      if (**pp == ':')
-       {
-         p = ++(*pp);
-#if 0
-         /* Possible future hook for nested types. */
-         if (**pp == '!')
-           {
-             list->field.bitpos = (long)-2; /* nested type */
-             p = ++(*pp);
-           }
-         else
-#endif
-           { /* Static class member.  */
-             list->field.bitpos = (long)-1;
-           }
-         while (*p != ';') p++;
-         list->field.bitsize = (long) savestring (*pp, p - *pp);
-         *pp = p + 1;
-         nfields++;
-         continue;
-       }
-       else if (**pp != ',')
-        /* Bad structure-type format.  */
-        return error_type (pp);
-
+         complain (&invalid_cpp_abbrev_complaint, *pp);
+       }
+      fip->list->field.type = read_type (pp, objfile);
       (*pp)++;                 /* Skip the comma.  */
-      list->field.bitpos = read_number (pp, ',');
-      list->field.bitsize = read_number (pp, ';');
+      fip->list->field.bitpos = read_number (pp, ';');
+      /* This field is unpacked.  */
+      fip->list->field.bitsize = 0;
+      fip->list->visibility = VISIBILITY_PRIVATE;
+    }
+  else if (*p == '_')
+    {
+      /* GNU C++ anonymous type.  */
+      complain (&stabs_general_complaint, "g++ anonymous type $_ not handled");
+    }
+  else
+    {
+      complain (&invalid_cpp_abbrev_complaint, *pp);
+    }
+}
 
+static void
+read_one_struct_field (fip, pp, p, type, objfile)
+     struct field_info *fip;
+     char **pp;
+     char *p;
+     struct type *type;
+     struct objfile *objfile;
+{
+  fip -> list -> field.name =
+    obsavestring (*pp, p - *pp, &objfile -> type_obstack);
+  *pp = p + 1;
+  
+  /* This means we have a visibility for a field coming. */
+  if (**pp == '/')
+    {
+      (*pp)++;
+      fip -> list -> visibility = *(*pp)++;
+      switch (fip -> list -> visibility)
+       {
+         case VISIBILITY_PRIVATE:
+         case VISIBILITY_PROTECTED:
+           break;
+         
+         case VISIBILITY_PUBLIC:
+           /* Nothing to do */
+           break;
+         
+         default:
+           /* Unknown visibility specifier. */
+           complain (&stabs_general_complaint,
+                     "unknown visibility specifier");
+           return;
+           break;
+       }
+    }
+  else
+    {
+      /* normal dbx-style format, no explicit visibility */
+      fip -> list -> visibility = VISIBILITY_PUBLIC;
+    }
+  
+  fip -> list -> field.type = read_type (pp, objfile);
+  if (**pp == ':')
+    {
+      p = ++(*pp);
 #if 0
-      /* FIXME-tiemann: Can't the compiler put out something which
-        lets us distinguish these? (or maybe just not put out anything
-        for the field).  What is the story here?  What does the compiler
-       really do?  Also, patch gdb.texinfo for this case; I document
-       it as a possible problem there.  Search for "DBX-style".  */
-
-      /* This is wrong because this is identical to the symbols
-        produced for GCC 0-size arrays.  For example:
-         typedef union {
-          int num;
-          char str[0];
-        } foo;
-        The code which dumped core in such circumstances should be
-        fixed not to dump core.  */
-
-      /* g++ -g0 can put out bitpos & bitsize zero for a static
-        field.  This does not give us any way of getting its
-        class, so we can't know its name.  But we can just
-        ignore the field so we don't dump core and other nasty
-        stuff.  */
-      if (list->field.bitpos == 0
-         && list->field.bitsize == 0)
+      /* Possible future hook for nested types. */
+      if (**pp == '!')
        {
-         complain (&dbx_class_complaint, 0);
-         /* Ignore this field.  */
-         list = list->next;
+         fip -> list -> field.bitpos = (long)-2; /* nested type */
+         p = ++(*pp);
        }
       else
+#endif
+       {
+         /* Static class member.  */
+         fip -> list -> field.bitpos = (long) -1;
+       }
+      while (*p != ';') 
+       {
+         p++;
+       }
+      fip -> list -> field.bitsize = (long) savestring (*pp, p - *pp);
+      *pp = p + 1;
+      return;
+    }
+  else if (**pp != ',')
+    {
+      /* Bad structure-type format.  */
+      complain (&stabs_general_complaint, "bad structure-type format");
+      return;
+    }
+  
+  (*pp)++;                     /* Skip the comma.  */
+  fip -> list -> field.bitpos = read_number (pp, ',');
+  fip -> list -> field.bitsize = read_number (pp, ';');
+  
+#if 0
+  /* FIXME-tiemann: Can't the compiler put out something which
+     lets us distinguish these? (or maybe just not put out anything
+     for the field).  What is the story here?  What does the compiler
+     really do?  Also, patch gdb.texinfo for this case; I document
+     it as a possible problem there.  Search for "DBX-style".  */
+  
+  /* This is wrong because this is identical to the symbols
+     produced for GCC 0-size arrays.  For example:
+     typedef union {
+     int num;
+     char str[0];
+     } foo;
+     The code which dumped core in such circumstances should be
+     fixed not to dump core.  */
+  
+  /* g++ -g0 can put out bitpos & bitsize zero for a static
+     field.  This does not give us any way of getting its
+     class, so we can't know its name.  But we can just
+     ignore the field so we don't dump core and other nasty
+     stuff.  */
+  if (fip -> list -> field.bitpos == 0 && fip -> list -> field.bitsize == 0)
+    {
+      complain (&dbx_class_complaint);
+      /* Ignore this field.  */
+      fip -> list = fip -> list -> next;
+    }
+  else
 #endif /* 0 */
+    {
+      /* Detect an unpacked field and mark it as such.
+        dbx gives a bit size for all fields.
+        Note that forward refs cannot be packed,
+        and treat enums as if they had the width of ints.  */
+      
+      if (TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_INT
+         && TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_ENUM)
        {
-         /* Detect an unpacked field and mark it as such.
-            dbx gives a bit size for all fields.
-            Note that forward refs cannot be packed,
-            and treat enums as if they had the width of ints.  */
-         if (TYPE_CODE (list->field.type) != TYPE_CODE_INT
-             && TYPE_CODE (list->field.type) != TYPE_CODE_ENUM)
-           list->field.bitsize = 0;
-         if ((list->field.bitsize == 8 * TYPE_LENGTH (list->field.type)
-              || (TYPE_CODE (list->field.type) == TYPE_CODE_ENUM
-                  && (list->field.bitsize
-                      == 8 * TYPE_LENGTH (lookup_fundamental_type (objfile, FT_INTEGER)))
-                  )
+         fip -> list -> field.bitsize = 0;
+       }
+      if ((fip -> list -> field.bitsize 
+          == 8 * TYPE_LENGTH (fip -> list -> field.type)
+          || (TYPE_CODE (fip -> list -> field.type) == TYPE_CODE_ENUM
+              && (fip -> list -> field.bitsize
+                  == 8 * TYPE_LENGTH (lookup_fundamental_type (objfile, FT_INTEGER)))
               )
-             &&
-             list->field.bitpos % 8 == 0)
-           list->field.bitsize = 0;
-         nfields++;
+          )
+         &&
+         fip -> list -> field.bitpos % 8 == 0)
+       {
+         fip -> list -> field.bitsize = 0;
        }
     }
+}
 
-  if (p[1] == ':')
-    /* chill the list of fields: the last entry (at the head)
-       is a partially constructed entry which we now scrub.  */
-    list = list->next;
 
-  /* Now create the vector of fields, and record how big it is.
-     We need this info to record proper virtual function table information
-     for this class's virtual functions.  */
+/* Read struct or class data fields.  They have the form:
 
-  TYPE_NFIELDS (type) = nfields;
-  TYPE_FIELDS (type) = (struct field *)
-    obstack_alloc (&objfile -> type_obstack, sizeof (struct field) * nfields);
+       NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
 
-  if (non_public_fields)
+   At the end, we see a semicolon instead of a field.
+
+   In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+   a static field.
+
+   The optional VISIBILITY is one of:
+
+       '/0'    (VISIBILITY_PRIVATE)
+       '/1'    (VISIBILITY_PROTECTED)
+       '/2'    (VISIBILITY_PUBLIC)
+
+   or nothing, for C style fields with public visibility. */
+       
+static int
+read_struct_fields (fip, pp, type, objfile)
+     struct field_info *fip;
+     char **pp;
+     struct type *type;
+     struct objfile *objfile;
+{
+  register char *p;
+  struct nextfield *new;
+
+  /* We better set p right now, in case there are no fields at all...    */
+
+  p = *pp;
+
+  /* Read each data member type until we find the terminating ';' at the end of
+     the data member list, or break for some other reason such as finding the
+     start of the member function list. */
+
+  while (**pp != ';')
     {
-      ALLOCATE_CPLUS_STRUCT_TYPE (type);
+      STABS_CONTINUE (pp);
+      /* Get space to record the next field's data.  */
+      new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+      make_cleanup (free, new);
+      memset (new, 0, sizeof (struct nextfield));
+      new -> next = fip -> list;
+      fip -> list = new;
 
-      TYPE_FIELD_PRIVATE_BITS (type) =
-         (B_TYPE *) obstack_alloc (&objfile -> type_obstack,
-                                   B_BYTES (nfields));
-      B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
+      /* Get the field name.  */
+      p = *pp;
+      if (*p == CPLUS_MARKER)
+       {
+         read_cpp_abbrev (fip, pp, type, objfile);
+         continue;
+       }
 
-      TYPE_FIELD_PROTECTED_BITS (type) =
-         (B_TYPE *) obstack_alloc (&objfile -> type_obstack,
-                                   B_BYTES (nfields));
-      B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
-    }
+      /* Look for the ':' that separates the field name from the field
+        values.  Data members are delimited by a single ':', while member
+        functions are delimited by a pair of ':'s.  When we hit the member
+        functions (if any), terminate scan loop and return. */
 
-  /* Copy the saved-up fields into the field vector.  */
+      while (*p != ':') 
+       {
+         p++;
+       }
 
-  for (n = nfields; list; list = list->next)
+      /* Check to see if we have hit the member functions yet.  */
+      if (p[1] == ':')
+       {
+         break;
+       }
+      read_one_struct_field (fip, pp, p, type, objfile);
+    }
+  if (p[1] == ':')
     {
-      n -= 1;
-      TYPE_FIELD (type, n) = list->field;
-      if (list->visibility == 0)
-       SET_TYPE_FIELD_PRIVATE (type, n);
-      else if (list->visibility == 1)
-       SET_TYPE_FIELD_PROTECTED (type, n);
+      /* chill the list of fields: the last entry (at the head) is a
+        partially constructed entry which we now scrub. */
+      fip -> list = fip -> list -> next;
     }
+  return 1;
+}
 
-  /* Now come the method fields, as NAME::methods
-     where each method is of the form TYPENUM,ARGS,...:PHYSNAME;
-     At the end, we see a semicolon instead of a field.
+/* The stabs for C++ derived classes contain baseclass information which
+   is marked by a '!' character after the total size.  This function is
+   called when we encounter the baseclass marker, and slurps up all the
+   baseclass information.
+
+   Immediately following the '!' marker is the number of base classes that
+   the class is derived from, followed by information for each base class.
+   For each base class, there are two visibility specifiers, a bit offset
+   to the base class information within the derived class, a reference to
+   the type for the base class, and a terminating semicolon.
+
+   A typical example, with two base classes, would be "!2,020,19;0264,21;".
+                                                      ^^ ^ ^ ^  ^ ^  ^
+       Baseclass information marker __________________|| | | |  | |  |
+       Number of baseclasses __________________________| | | |  | |  |
+       Visibility specifiers (2) ________________________| | |  | |  |
+       Offset in bits from start of class _________________| |  | |  |
+       Type number for base class ___________________________|  | |  |
+       Visibility specifiers (2) _______________________________| |  |
+       Offset in bits from start of class ________________________|  |
+       Type number of base class ____________________________________|
+ */
+
+static int
+read_baseclasses (fip, pp, type, objfile)
+     struct field_info *fip;
+     char **pp;
+     struct type *type;
+     struct objfile *objfile;
+{
+  int i;
+  struct nextfield *new;
 
-     For the case of overloaded operators, the format is
-     op$::*.methods, where $ is the CPLUS_MARKER (usually '$'),
-     `*' holds the place for an operator name (such as `+=')
-     and `.' marks the end of the operator name.  */
-  if (p[1] == ':')
+  if (**pp != '!')
+    {
+      return 1;
+    }
+  else
     {
-      /* Now, read in the methods.  To simplify matters, we
-        "unread" the name that has been read, so that we can
-        start from the top.  */
+      /* Skip the '!' baseclass information marker. */
+      (*pp)++;
+    }
 
-      ALLOCATE_CPLUS_STRUCT_TYPE (type);
-      /* For each list of method lists... */
-      do
-       {
-         int i;
-         struct next_fnfield *sublist = 0;
-         struct type *look_ahead_type = NULL;
-         int length = 0;
-         struct next_fnfieldlist *new_mainlist;
-         char *main_fn_name;
+  ALLOCATE_CPLUS_STRUCT_TYPE (type);
+  TYPE_N_BASECLASSES (type) = read_number (pp, ',');
 
-         new_mainlist = (struct next_fnfieldlist *)
-             alloca (sizeof (struct next_fnfieldlist));
-         memset (new_mainlist, 0, sizeof (struct next_fnfieldlist));
+#if 0
+  /* Some stupid compilers have trouble with the following, so break
+     it up into simpler expressions.  */
+  TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *)
+    TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type)));
+#else
+  {
+    int num_bytes = B_BYTES (TYPE_N_BASECLASSES (type));
+    char *pointer;
 
-         p = *pp;
+    pointer = (char *) TYPE_ALLOC (type, num_bytes);
+    TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) pointer;
+  }
+#endif /* 0 */
 
-         /* read in the name.  */
-         while (*p != ':') p++;
-         if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == CPLUS_MARKER)
-           {
-             /* This is a completely wierd case.  In order to stuff in the
-                names that might contain colons (the usual name delimiter),
-                Mike Tiemann defined a different name format which is
-                signalled if the identifier is "op$".  In that case, the
-                format is "op$::XXXX." where XXXX is the name.  This is
-                used for names like "+" or "=".  YUUUUUUUK!  FIXME!  */
-             /* This lets the user type "break operator+".
-                We could just put in "+" as the name, but that wouldn't
-                work for "*".  */
-             static char opname[32] = {'o', 'p', CPLUS_MARKER};
-             char *o = opname + 3;
-
-             /* Skip past '::'.  */
-             *pp = p + 2;
-             if (**pp == '\\') *pp = next_symbol_text ();
-             p = *pp;
-             while (*p != '.')
-               *o++ = *p++;
-             main_fn_name = savestring (opname, o - opname);
-             /* Skip past '.'  */
-             *pp = p + 1;
-           }
-         else
-           {
-             main_fn_name = savestring (*pp, p - *pp);
-             /* Skip past '::'.  */
-             *pp = p + 2;
-           }
-         new_mainlist->fn_fieldlist.name = main_fn_name;
+  B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type));
 
-         do
-           {
-             struct next_fnfield *new_sublist =
-               (struct next_fnfield *) alloca (sizeof (struct next_fnfield));
-             memset (new_sublist, 0, sizeof (struct next_fnfield));
+  for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+    {
+      new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+      make_cleanup (free, new);
+      memset (new, 0, sizeof (struct nextfield));
+      new -> next = fip -> list;
+      fip -> list = new;
+      new -> field.bitsize = 0;        /* this should be an unpacked field! */
 
-             /* Check for and handle cretinous dbx symbol name continuation!  */
-             if (look_ahead_type == NULL) /* Normal case. */
-               {
-                 if (**pp == '\\') *pp = next_symbol_text ();
+      STABS_CONTINUE (pp);
+      switch (*(*pp)++)
+       {
+         case '0':
+           /* Nothing to do. */
+           break;
+         case '1':
+           SET_TYPE_FIELD_VIRTUAL (type, i);
+           break;
+         default:
+           /* Bad visibility format.  */
+           return 0;
+       }
 
-                 new_sublist->fn_field.type = read_type (pp, objfile);
-                 if (**pp != ':')
-                   /* Invalid symtab info for method.  */
-                   return error_type (pp);
-               }
-             else
-               { /* g++ version 1 kludge */
-                 new_sublist->fn_field.type = look_ahead_type;
-                 look_ahead_type = NULL;
-               }
-
-             *pp += 1;
-             p = *pp;
-             while (*p != ';') p++;
-
-             /* If this is just a stub, then we don't have the
-                real name here.  */
-             if (TYPE_FLAGS (new_sublist->fn_field.type) & TYPE_FLAG_STUB)
-               new_sublist->fn_field.is_stub = 1;
-             new_sublist->fn_field.physname = savestring (*pp, p - *pp);
-             *pp = p + 1;
-
-             /* Set this method's visibility fields.  */
-             switch (*(*pp)++ - '0')
-               {
-               case 0:
-                 new_sublist->fn_field.is_private = 1;
-                 break;
-               case 1:
-                 new_sublist->fn_field.is_protected = 1;
-                 break;
-               }
+      new -> visibility = *(*pp)++;
+      switch (new -> visibility)
+       {
+         case VISIBILITY_PRIVATE:
+         case VISIBILITY_PROTECTED:
+         case VISIBILITY_PUBLIC:
+           break;
+         default:
+           /* Bad visibility format.  */
+           return 0;
+       }
 
-             if (**pp == '\\') *pp = next_symbol_text ();
-             switch (**pp)
-               {
-               case 'A': /* Normal functions. */
-                 new_sublist->fn_field.is_const = 0;
-                 new_sublist->fn_field.is_volatile = 0;
-                 (*pp)++;
-                 break;
-               case 'B': /* `const' member functions. */
-                 new_sublist->fn_field.is_const = 1;
-                 new_sublist->fn_field.is_volatile = 0;
-                 (*pp)++;
-                 break;
-               case 'C': /* `volatile' member function. */
-                 new_sublist->fn_field.is_const = 0;
-                 new_sublist->fn_field.is_volatile = 1;
-                 (*pp)++;
-                 break;
-               case 'D': /* `const volatile' member function. */
-                 new_sublist->fn_field.is_const = 1;
-                 new_sublist->fn_field.is_volatile = 1;
-                 (*pp)++;
-                 break;
-               case '*': /* File compiled with g++ version 1 -- no info */
-               case '?':
-               case '.':
-                 break;
-               default:
-                 complain (&const_vol_complaint, (char *) (long) **pp);
-                 break;
-               }
+      /* The remaining value is the bit offset of the portion of the object
+        corresponding to this baseclass.  Always zero in the absence of
+        multiple inheritance.  */
 
-             switch (*(*pp)++)
-               {
-               case '*':
-                 /* virtual member function, followed by index.  */
-                 /* The sign bit is set to distinguish pointers-to-methods
-                    from virtual function indicies.  Since the array is
-                    in words, the quantity must be shifted left by 1
-                    on 16 bit machine, and by 2 on 32 bit machine, forcing
-                    the sign bit out, and usable as a valid index into
-                    the array.  Remove the sign bit here.  */
-                 new_sublist->fn_field.voffset =
-                     (0x7fffffff & read_number (pp, ';')) + 2;
-
-                 if (**pp == '\\') *pp = next_symbol_text ();
-
-                 if (**pp == ';' || **pp == '\0')
-                   /* Must be g++ version 1.  */
-                   new_sublist->fn_field.fcontext = 0;
-                 else
-                   {
-                     /* Figure out from whence this virtual function came.
-                        It may belong to virtual function table of
-                        one of its baseclasses.  */
-                     look_ahead_type = read_type (pp, objfile);
-                     if (**pp == ':')
-                       { /* g++ version 1 overloaded methods. */ }
-                     else
-                       {
-                         new_sublist->fn_field.fcontext = look_ahead_type;
-                         if (**pp != ';')
-                           return error_type (pp);
-                         else
-                           ++*pp;
-                         look_ahead_type = NULL;
-                       }
-                   }
-                 break;
-
-               case '?':
-                 /* static member function.  */
-                 new_sublist->fn_field.voffset = VOFFSET_STATIC;
-                 if (strncmp (new_sublist->fn_field.physname,
-                              main_fn_name, strlen (main_fn_name)))
-                   new_sublist->fn_field.is_stub = 1;
-                 break;
-
-               default:
-                 /* error */
-                 complain (&member_fn_complaint, (char *) (long) (*pp)[-1]);
-                 /* Fall through into normal member function.  */
-
-               case '.':
-                 /* normal member function.  */
-                 new_sublist->fn_field.voffset = 0;
-                 new_sublist->fn_field.fcontext = 0;
-                 break;
-               }
+      new -> field.bitpos = read_number (pp, ',');
 
-             new_sublist->next = sublist;
-             sublist = new_sublist;
-             length++;
-             if (**pp == '\\') *pp = next_symbol_text ();
-           }
-         while (**pp != ';' && **pp != '\0');
-
-         *pp += 1;
-
-         new_mainlist->fn_fieldlist.fn_fields =
-           (struct fn_field *) obstack_alloc (&objfile -> type_obstack,
-                                              sizeof (struct fn_field) * length);
-         for (i = length; (i--, sublist); sublist = sublist->next)
-           new_mainlist->fn_fieldlist.fn_fields[i] = sublist->fn_field;
-
-         new_mainlist->fn_fieldlist.length = length;
-         new_mainlist->next = mainlist;
-         mainlist = new_mainlist;
-         nfn_fields++;
-         total_length += length;
-         if (**pp == '\\') *pp = next_symbol_text ();
-       }
-      while (**pp != ';');
+      /* The last piece of baseclass information is the type of the base
+        class.  Read it, and remember it's type name as this field's name. */
+
+      new -> field.type = read_type (pp, objfile);
+      new -> field.name = type_name_no_tag (new -> field.type);
+
+      /* skip trailing ';' and bump count of number of fields seen */
+      (*pp)++;
     }
+  return 1;
+}
 
-  *pp += 1;
+/* The tail end of stabs for C++ classes that contain a virtual function
+   pointer contains a tilde, a %, and a type number.
+   The type number refers to the base class (possibly this class itself) which
+   contains the vtable pointer for the current class.
 
+   This function is called when we have parsed all the method declarations,
+   so we can look for the vptr base class info.  */
 
-  if (nfn_fields)
-    {
-      TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
-       obstack_alloc (&objfile -> type_obstack,
-                      sizeof (struct fn_fieldlist) * nfn_fields);
-      TYPE_NFN_FIELDS (type) = nfn_fields;
-      TYPE_NFN_FIELDS_TOTAL (type) = total_length;
-    }
+static int
+read_tilde_fields (fip, pp, type, objfile)
+     struct field_info *fip;
+     char **pp;
+     struct type *type;
+     struct objfile *objfile;
+{
+  register char *p;
 
-  {
-    int i;
-    for (i = 0; i < TYPE_N_BASECLASSES (type); ++i)
-      {
-       if (TYPE_CODE (TYPE_BASECLASS (type, i)) == TYPE_CODE_UNDEF)
-         /* @@ Memory leak on objfile->type_obstack?  */
-         return error_type (pp);
-       TYPE_NFN_FIELDS_TOTAL (type) +=
-         TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, i));
-      }
-  }
+  STABS_CONTINUE (pp);
 
-  for (n = nfn_fields; mainlist; mainlist = mainlist->next) {
-    --n;                      /* Circumvent Sun3 compiler bug */
-    TYPE_FN_FIELDLISTS (type)[n] = mainlist->fn_fieldlist;
-  }
+  /* If we are positioned at a ';', then skip it. */
+  if (**pp == ';')
+    {
+      (*pp)++;
+    }
 
   if (**pp == '~')
     {
-      *pp += 1;
+      (*pp)++;
 
       if (**pp == '=' || **pp == '+' || **pp == '-')
        {
          /* Obsolete flags that used to indicate the presence
             of constructors and/or destructors. */
-         *pp += 1;
+         (*pp)++;
        }
 
       /* Read either a '%' or the final ';'.  */
       if (*(*pp)++ == '%')
        {
-         /* We'd like to be able to derive the vtable pointer field
-            from the type information, but when it's inherited, that's
-            hard.  A reason it's hard is because we may read in the
-            info about a derived class before we read in info about
-            the base class that provides the vtable pointer field.
-            Once the base info has been read, we could fill in the info
-            for the derived classes, but for the fact that by then,
-            we don't remember who needs what.  */
-
-#if 0
-         int predicted_fieldno = -1;
-#endif
-
-         /* Now we must record the virtual function table pointer's
-            field information.  */
+         /* The next number is the type number of the base class
+            (possibly our own class) which supplies the vtable for
+            this class.  Parse it out, and search that class to find
+            its vtable pointer, and install those into TYPE_VPTR_BASETYPE
+            and TYPE_VPTR_FIELDNO.  */
 
          struct type *t;
          int i;
 
-
-#if 0
-         {
-           /* In version 2, we derive the vfield ourselves.  */
-           for (n = 0; n < nfields; n++)
-             {
-               if (! strncmp (TYPE_FIELD_NAME (type, n), vptr_name, 
-                              sizeof (vptr_name) -1))
-                 {
-                   predicted_fieldno = n;
-                   break;
-                 }
-             }
-           if (predicted_fieldno < 0)
-             for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
-               if (! TYPE_FIELD_VIRTUAL (type, n)
-                   && TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, n)) >= 0)
-                 {
-                   predicted_fieldno = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, n));
-                   break;
-                 }
-         }
-#endif
-
          t = read_type (pp, objfile);
          p = (*pp)++;
          while (*p != '\0' && *p != ';')
-           p++;
+           {
+             p++;
+           }
          if (*p == '\0')
-           /* Premature end of symbol.  */
-           return error_type (pp);
+           {
+             /* Premature end of symbol.  */
+             return 0;
+           }
          
          TYPE_VPTR_BASETYPE (type) = t;
-         if (type == t)
+         if (type == t)                /* Our own class provides vtbl ptr */
            {
-             if (TYPE_FIELD_NAME (t, TYPE_N_BASECLASSES (t)) == 0)
+             for (i = TYPE_NFIELDS (t) - 1;
+                  i >= TYPE_N_BASECLASSES (t);
+                  --i)
                {
-                 /* FIXME-tiemann: what's this?  */
-#if 0
-                 TYPE_VPTR_FIELDNO (type) = i = TYPE_N_BASECLASSES (t);
-#else
-                 error_type (pp);
-#endif
+                 if (! strncmp (TYPE_FIELD_NAME (t, i), vptr_name, 
+                                sizeof (vptr_name) - 1))
+                   {
+                     TYPE_VPTR_FIELDNO (type) = i;
+                     goto gotit;
+                   }
                }
-             else for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); --i)
-               if (! strncmp (TYPE_FIELD_NAME (t, i), vptr_name, 
-                              sizeof (vptr_name) - 1))
-                 {
-                   TYPE_VPTR_FIELDNO (type) = i;
-                   break;
-                 }
-             if (i < 0)
-               /* Virtual function table field not found.  */
-               return error_type (pp);
+             /* Virtual function table field not found.  */
+             complain (vtbl_notfound_complaint, TYPE_NAME (type));
+             return 0;
            }
          else
-           TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t);
-
-#if 0
-         if (TYPE_VPTR_FIELDNO (type) != predicted_fieldno)
-           error ("TYPE_VPTR_FIELDNO miscalculated");
-#endif
+           {
+             TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t);
+           }
 
+    gotit:
          *pp = p + 1;
        }
     }
+  return 1;
+}
 
-  return type;
+static int
+attach_fn_fields_to_type (fip, type)
+     struct field_info *fip;
+     register struct type *type;
+{
+  register int n;
+
+  for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
+    {
+      if (TYPE_CODE (TYPE_BASECLASS (type, n)) == TYPE_CODE_UNDEF)
+       {
+         /* @@ Memory leak on objfile -> type_obstack?  */
+         return 0;
+       }
+      TYPE_NFN_FIELDS_TOTAL (type) +=
+       TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, n));
+    }
+
+  for (n = TYPE_NFN_FIELDS (type);
+       fip -> fnlist != NULL;
+       fip -> fnlist = fip -> fnlist -> next)
+    {
+      --n;                      /* Circumvent Sun3 compiler bug */
+      TYPE_FN_FIELDLISTS (type)[n] = fip -> fnlist -> fn_fieldlist;
+    }
+  return 1;
+}
+
+/* Create the vector of fields, and record how big it is.
+   We need this info to record proper virtual function table information
+   for this class's virtual functions.  */
+
+static int
+attach_fields_to_type (fip, type, objfile)
+     struct field_info *fip;
+     register struct type *type;
+     struct objfile *objfile;
+{
+  register int nfields = 0;
+  register int non_public_fields = 0;
+  register struct nextfield *scan;
+
+  /* Count up the number of fields that we have, as well as taking note of
+     whether or not there are any non-public fields, which requires us to
+     allocate and build the private_field_bits and protected_field_bits
+     bitfields. */
+
+  for (scan = fip -> list; scan != NULL; scan = scan -> next)
+    {
+      nfields++;
+      if (scan -> visibility != VISIBILITY_PUBLIC)
+       {
+         non_public_fields++;
+       }
+    }
+
+  /* Now we know how many fields there are, and whether or not there are any
+     non-public fields.  Record the field count, allocate space for the
+     array of fields, and create blank visibility bitfields if necessary. */
+
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type) = (struct field *)
+    TYPE_ALLOC (type, sizeof (struct field) * nfields);
+  memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+
+  if (non_public_fields)
+    {
+      ALLOCATE_CPLUS_STRUCT_TYPE (type);
+
+      TYPE_FIELD_PRIVATE_BITS (type) =
+       (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+      B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
+
+      TYPE_FIELD_PROTECTED_BITS (type) =
+       (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+      B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
+    }
+
+  /* Copy the saved-up fields into the field vector.  Start from the head
+     of the list, adding to the tail of the field array, so that they end
+     up in the same order in the array in which they were added to the list. */
+
+  while (nfields-- > 0)
+    {
+      TYPE_FIELD (type, nfields) = fip -> list -> field;
+      switch (fip -> list -> visibility)
+       {
+         case VISIBILITY_PRIVATE:
+           SET_TYPE_FIELD_PRIVATE (type, nfields);
+           break;
+
+         case VISIBILITY_PROTECTED:
+           SET_TYPE_FIELD_PROTECTED (type, nfields);
+           break;
+
+         case VISIBILITY_PUBLIC:
+           break;
+
+         default:
+           /* Should warn about this unknown visibility? */
+           break;
+       }
+      fip -> list = fip -> list -> next;
+    }
+  return 1;
+}
+
+/* Read the description of a structure (or union type) and return an object
+   describing the type.
+
+   PP points to a character pointer that points to the next unconsumed token
+   in the the stabs string.  For example, given stabs "A:T4=s4a:1,0,32;;",
+   *PP will point to "4a:1,0,32;;".
+
+   TYPE points to an incomplete type that needs to be filled in.
+
+   OBJFILE points to the current objfile from which the stabs information is
+   being read.  (Note that it is redundant in that TYPE also contains a pointer
+   to this same objfile, so it might be a good idea to eliminate it.  FIXME). 
+   */
+
+static struct type *
+read_struct_type (pp, type, objfile)
+     char **pp;
+     struct type *type;
+     struct objfile *objfile;
+{
+  struct cleanup *back_to;
+  struct field_info fi;
+
+  fi.list = NULL;
+  fi.fnlist = NULL;
+
+  back_to = make_cleanup (null_cleanup, 0);
+
+  INIT_CPLUS_SPECIFIC (type);
+  TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+
+  /* First comes the total size in bytes.  */
+
+  TYPE_LENGTH (type) = read_number (pp, 0);
+
+  /* Now read the baseclasses, if any, read the regular C struct or C++
+     class member fields, attach the fields to the type, read the C++
+     member functions, attach them to the type, and then read any tilde
+     field (baseclass specifier for the class holding the main vtable). */
+
+  if (!read_baseclasses (&fi, pp, type, objfile))
+    {
+      do_cleanups (back_to);
+      return (error_type (pp));
+    }
+  if (!read_struct_fields (&fi, pp, type, objfile))
+    {
+      do_cleanups (back_to);
+      return (error_type (pp));
+    }
+  if (!attach_fields_to_type (&fi, type, objfile))
+    {
+      do_cleanups (back_to);
+      return (error_type (pp));
+    }
+  if (!read_member_functions (&fi, pp, type, objfile))
+    {
+      do_cleanups (back_to);
+      return (error_type (pp));
+    }
+  if (!attach_fn_fields_to_type (&fi, type))
+    {
+      do_cleanups (back_to);
+      return (error_type (pp));
+    }
+  if (!read_tilde_fields (&fi, pp, type, objfile))
+    {
+      do_cleanups (back_to);
+      return (error_type (pp));
+    }
+
+  do_cleanups (back_to);
+  return (type);
 }
 
 /* Read a definition of an array type,
@@ -2036,14 +2412,14 @@ read_array_type (pp, type, objfile)
 
   if (!(**pp >= '0' && **pp <= '9'))
     {
-      *pp += 1;
+      (*pp)++;
       adjustable = 1;
     }
   lower = read_number (pp, ';');
 
   if (!(**pp >= '0' && **pp <= '9'))
     {
-      *pp += 1;
+      (*pp)++;
       adjustable = 1;
     }
   upper = read_number (pp, ';');
@@ -2056,39 +2432,17 @@ read_array_type (pp, type, objfile)
       upper = -1;
     }
 
-  {
-    /* Create range type.  */
-    range_type = (struct type *)
-      obstack_alloc (&objfile -> type_obstack, sizeof (struct type));
-    memset (range_type, 0, sizeof (struct type));
-    TYPE_OBJFILE (range_type) = objfile;
-    TYPE_CODE (range_type) = TYPE_CODE_RANGE;
-    TYPE_TARGET_TYPE (range_type) = index_type;
-
-    /* This should never be needed.  */
-    TYPE_LENGTH (range_type) = sizeof (int);
-
-    TYPE_NFIELDS (range_type) = 2;
-    TYPE_FIELDS (range_type) =
-      (struct field *) obstack_alloc (&objfile -> type_obstack,
-                                     2 * sizeof (struct field));
-    TYPE_FIELD_BITPOS (range_type, 0) = lower;
-    TYPE_FIELD_BITPOS (range_type, 1) = upper;
-  }
-
-  TYPE_CODE (type) = TYPE_CODE_ARRAY;
-  TYPE_TARGET_TYPE (type) = element_type;
-  TYPE_LENGTH (type) = (upper - lower + 1) * TYPE_LENGTH (element_type);
-  TYPE_NFIELDS (type) = 1;
-  TYPE_FIELDS (type) =
-    (struct field *) obstack_alloc (&objfile -> type_obstack,
-                                   sizeof (struct field));
-  TYPE_FIELD_TYPE (type, 0) = range_type;
+  range_type =
+    create_range_type ((struct type *) NULL, index_type, lower, upper);
+  type = create_array_type (type, element_type, range_type);
 
   /* If we have an array whose element type is not yet known, but whose
      bounds *are* known, record it to be adjusted at the end of the file.  */
+
   if (TYPE_LENGTH (element_type) == 0 && !adjustable)
-    add_undefined_type (type);
+    {
+      add_undefined_type (type);
+    }
 
   return type;
 }
@@ -2130,18 +2484,18 @@ read_enum_type (pp, type, objfile)
      A semicolon or comma instead of a NAME means the end.  */
   while (**pp && **pp != ';' && **pp != ',')
     {
-      /* Check for and handle cretinous dbx symbol name continuation!  */
-      if (**pp == '\\')        *pp = next_symbol_text ();
-
+      STABS_CONTINUE (pp);
       p = *pp;
       while (*p != ':') p++;
       name = obsavestring (*pp, p - *pp, &objfile -> symbol_obstack);
       *pp = p + 1;
       n = read_number (pp, ',');
 
-      sym = (struct symbol *) obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+      sym = (struct symbol *)
+       obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
       memset (sym, 0, sizeof (struct symbol));
       SYMBOL_NAME (sym) = name;
+      SYMBOL_LANGUAGE (sym) = current_subfile -> language;
       SYMBOL_CLASS (sym) = LOC_CONST;
       SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
       SYMBOL_VALUE (sym) = n;
@@ -2159,8 +2513,8 @@ read_enum_type (pp, type, objfile)
   TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
   TYPE_NFIELDS (type) = nsyms;
   TYPE_FIELDS (type) = (struct field *)
-    obstack_alloc (&objfile -> type_obstack,
-                  sizeof (struct field) * nsyms);
+    TYPE_ALLOC (type, sizeof (struct field) * nsyms);
+  memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nsyms);
 
   /* Find the symbols for the values and put them into the type.
      The symbols can be found in the symlist that we put them on
@@ -2192,10 +2546,10 @@ read_enum_type (pp, type, objfile)
   /* This screws up perfectly good C programs with enums.  FIXME.  */
   /* Is this Modula-2's BOOLEAN type?  Flag it as such if so. */
   if(TYPE_NFIELDS(type) == 2 &&
-     ((!strcmp(TYPE_FIELD_NAME(type,0),"TRUE") &&
-       !strcmp(TYPE_FIELD_NAME(type,1),"FALSE")) ||
-      (!strcmp(TYPE_FIELD_NAME(type,1),"TRUE") &&
-       !strcmp(TYPE_FIELD_NAME(type,0),"FALSE"))))
+     ((STREQ(TYPE_FIELD_NAME(type,0),"TRUE") &&
+       STREQ(TYPE_FIELD_NAME(type,1),"FALSE")) ||
+      (STREQ(TYPE_FIELD_NAME(type,1),"TRUE") &&
+       STREQ(TYPE_FIELD_NAME(type,0),"FALSE"))))
      TYPE_CODE(type) = TYPE_CODE_BOOL;
 #endif
 
@@ -2454,6 +2808,7 @@ read_range_type (pp, typenums, objfile)
   int n2bits, n3bits;
   int self_subrange;
   struct type *result_type;
+  struct type *index_type;
 
   /* First comes a type we are a subrange of.
      In C it is usually 0, 1 or the type being defined.  */
@@ -2503,11 +2858,7 @@ read_range_type (pp, typenums, objfile)
 
       if (got_signed || got_unsigned)
        {
-         result_type = (struct type *)
-           obstack_alloc (&objfile -> type_obstack,
-                          sizeof (struct type));
-         memset (result_type, 0, sizeof (struct type));
-         TYPE_OBJFILE (result_type) = objfile;
+         result_type = alloc_type (objfile);
          TYPE_LENGTH (result_type) = nbits / TARGET_CHAR_BIT;
          TYPE_CODE (result_type) = TYPE_CODE_INT;
          if (got_unsigned)
@@ -2616,30 +2967,15 @@ read_range_type (pp, typenums, objfile)
   if (self_subrange)
     return error_type (pp);
 
-  result_type = (struct type *)
-    obstack_alloc (&objfile -> type_obstack, sizeof (struct type));
-  memset (result_type, 0, sizeof (struct type));
-  TYPE_OBJFILE (result_type) = objfile;
-
-  TYPE_CODE (result_type) = TYPE_CODE_RANGE;
-
-  TYPE_TARGET_TYPE (result_type) = *dbx_lookup_type(rangenums);
-  if (TYPE_TARGET_TYPE (result_type) == 0) {
-    complain (&range_type_base_complaint, (char *) rangenums[1]);
-    TYPE_TARGET_TYPE (result_type) = lookup_fundamental_type (objfile, FT_INTEGER);
-  }
-
-  TYPE_NFIELDS (result_type) = 2;
-  TYPE_FIELDS (result_type) =
-    (struct field *) obstack_alloc (&objfile -> type_obstack,
-                                   2 * sizeof (struct field));
-  memset (TYPE_FIELDS (result_type), 0, 2 * sizeof (struct field));
-  TYPE_FIELD_BITPOS (result_type, 0) = n2;
-  TYPE_FIELD_BITPOS (result_type, 1) = n3;
-
-  TYPE_LENGTH (result_type) = TYPE_LENGTH (TYPE_TARGET_TYPE (result_type));
+  index_type = *dbx_lookup_type (rangenums);
+  if (index_type == NULL)
+    {
+      complain (&range_type_base_complaint, rangenums[1]);
+      index_type = lookup_fundamental_type (objfile, FT_INTEGER);
+    }
 
-  return result_type;
+  result_type = create_range_type ((struct type *) NULL, index_type, n2, n3);
+  return (result_type);
 }
 
 /* Read a number from the string pointed to by *PP.
@@ -2705,15 +3041,11 @@ read_args (pp, end, objfile)
       if (**pp != ',')
        /* Invalid argument list: no ','.  */
        return (struct type **)-1;
-      *pp += 1;
-
-      /* Check for and handle cretinous dbx symbol name continuation! */
-      if (**pp == '\\')
-       *pp = next_symbol_text ();
-
+      (*pp)++;
+      STABS_CONTINUE (pp);
       types[n++] = read_type (pp, objfile);
     }
-  *pp += 1;                    /* get past `end' (the ':' character) */
+  (*pp)++;                     /* get past `end' (the ':' character) */
 
   if (n == 1)
     {
@@ -2819,7 +3151,7 @@ cleanup_undefined_types ()
                            && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
                            && (TYPE_CODE (SYMBOL_TYPE (sym)) ==
                                TYPE_CODE (*type))
-                           && !strcmp (SYMBOL_NAME (sym), typename))
+                           && STREQ (SYMBOL_NAME (sym), typename))
                          {
                            memcpy (*type, SYMBOL_TYPE (sym),
                                    sizeof (struct type));
@@ -2876,7 +3208,7 @@ scan_file_globals (objfile)
   if (objfile->msymbols == 0)          /* Beware the null file.  */
     return;
 
-  for (msymbol = objfile -> msymbols; msymbol -> name != NULL; msymbol++)
+  for (msymbol = objfile -> msymbols; SYMBOL_NAME (msymbol) != NULL; msymbol++)
     {
       QUIT;
 
@@ -2885,12 +3217,12 @@ scan_file_globals (objfile)
       /* Get the hash index and check all the symbols
         under that hash index. */
 
-      hash = hashname (msymbol -> name);
+      hash = hashname (SYMBOL_NAME (msymbol));
 
       for (sym = global_sym_chain[hash]; sym;)
        {
-         if (*(msymbol -> name) == SYMBOL_NAME (sym)[0]
-             && !strcmp(msymbol -> name + 1, SYMBOL_NAME (sym) + 1))
+         if (SYMBOL_NAME (msymbol)[0] == SYMBOL_NAME (sym)[0] &&
+             STREQ(SYMBOL_NAME (msymbol) + 1, SYMBOL_NAME (sym) + 1))
            {
              /* Splice this symbol out of the hash chain and
                 assign the value we have to it. */
@@ -2909,11 +3241,11 @@ scan_file_globals (objfile)
 
              if (SYMBOL_CLASS (sym) == LOC_BLOCK)
                {
-                 fix_common_block (sym, msymbol -> address);
+                 fix_common_block (sym, SYMBOL_VALUE_ADDRESS (msymbol));
                }
              else
                {
-                 SYMBOL_VALUE_ADDRESS (sym) = msymbol -> address;
+                 SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msymbol);
                }
              
              if (prev)
@@ -2981,7 +3313,6 @@ void end_stabs ()
 
 void
 finish_global_stabs (objfile)
-
      struct objfile *objfile;
 {
   if (global_stabs)
This page took 0.088169 seconds and 4 git commands to generate.