Break out symbol-table-building routines
authorJohn Gilmore <gnu@cygnus>
Sat, 26 Oct 1991 07:21:30 +0000 (07:21 +0000)
committerJohn Gilmore <gnu@cygnus>
Sat, 26 Oct 1991 07:21:30 +0000 (07:21 +0000)
from dbxread.c, so they can be shared with xcoffread.c.

gdb/ChangeLog
gdb/buildsym.c [new file with mode: 0644]
gdb/buildsym.h [new file with mode: 0644]
gdb/dbxread.c

index 139a92433a0f622a637e58bde6a10b29389bc1c1..2a50492afe5932f5423d3e307a33311f82730ada 100644 (file)
@@ -1,3 +1,10 @@
+Sat Oct 26 00:16:32 1991  John Gilmore  (gnu at cygus.com)
+
+       * buildsym.c:  New file.  Breaks out symbol-table-building routines
+       from dbxread.c, so they can be shared with xcoffread.c.
+       * buildsym.h:  New file.  Declarations for buildsym.c users.
+       * dbxread.c:  Remove large chunks into buildsym.c.
+
 Fri Oct 25 18:59:32 1991  Per Bothner  (bothner at cygnus.com)
 
        Various fixes to improve g++ debugging.
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
new file mode 100644 (file)
index 0000000..2920b86
--- /dev/null
@@ -0,0 +1,2791 @@
+/* Build symbol tables in GDB's internal format.
+   Copyright (C) 1986-1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* This module provides subroutines used for creating and adding to
+   the symbol table.  These routines are called from various symbol-
+   file-reading routines.  
+
+   They originated in dbxread.c of gdb-4.2, and were split out to
+   make xcoffread.c more maintainable by sharing code.  */
+
+#include "defs.h"
+#include "param.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "breakpoint.h"
+#include "gdbcore.h"           /* for bfd stuff for symfile.h */
+#include "symfile.h"           /* Needed for "struct complaint" */
+#include "stab.gnu.h"          /* We always use GNU stabs, not native */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Ask buildsym.h to define the vars it normally declares `extern'.  */
+#define        EXTERN  /**/
+#include "buildsym.h"          /* Our own declarations */
+#undef EXTERN
+
+extern void qsort ();
+extern double atof ();
+
+/* Things we export from outside, and probably shouldn't.  FIXME.  */
+extern void new_object_header_files ();
+extern void start_subfile ();
+extern char *next_symbol_text ();
+extern int hashname ();
+\f
+static struct symbol *define_symbol ();
+static void cleanup_undefined_types ();
+static void fix_common_block ();
+
+static const char vptr_name[] = { '_','v','p','t','r',CPLUS_MARKER,'\0' };
+static const char vb_name[] =   { '_','v','b',CPLUS_MARKER,'\0' };
+
+/* Define this as 1 if a pcc declaration of a char or short argument
+   gives the correct address.  Otherwise assume pcc gives the
+   address of the corresponding int, which is not the same on a
+   big-endian machine.  */
+
+#ifndef BELIEVE_PCC_PROMOTION
+#define BELIEVE_PCC_PROMOTION 0
+#endif
+
+/* Make a list of forward references which haven't been defined.  */
+static struct type **undef_types;
+static int undef_types_allocated, undef_types_length;
+
+\f
+/* Complaints about the symbols we have encountered.  */
+
+struct complaint innerblock_complaint =
+  {"inner block not inside outer block in %s", 0, 0};
+
+struct complaint blockvector_complaint = 
+  {"block at %x out of order", 0, 0};
+
+#if 0
+struct complaint dbx_class_complaint =
+  {"encountered DBX-style class variable debugging information.\n\
+You seem to have compiled your program with \
+\"g++ -g0\" instead of \"g++ -g\".\n\
+Therefore GDB will not know about your class variables", 0, 0};
+#endif
+
+struct complaint const_vol_complaint =
+  {"const/volatile indicator missing (ok if using g++ v1.x), got '%c'", 0, 0};
+
+struct complaint error_type_complaint =
+  {"debug info mismatch between compiler and debugger", 0, 0};
+
+struct complaint invalid_member_complaint =
+  {"invalid (minimal) member type data format at symtab pos %d.", 0, 0};
+
+struct complaint range_type_base_complaint =
+  {"base type %d of range type is not defined", 0, 0};
+\f
+/* Look up a dbx type-number pair.  Return the address of the slot
+   where the type for that number-pair is stored.
+   The number-pair is in TYPENUMS.
+
+   This can be used for finding the type associated with that pair
+   or for associating a new type with the pair.  */
+
+struct type **
+dbx_lookup_type (typenums)
+     int typenums[2];
+{
+  register int filenum = typenums[0], index = typenums[1];
+
+  if (filenum < 0 || filenum >= n_this_object_header_files)
+    error ("Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+          filenum, index, symnum);
+
+  if (filenum == 0)
+    {
+      /* Type is defined outside of header files.
+        Find it in this object file's type vector.  */
+      while (index >= type_vector_length)
+       {
+         type_vector_length *= 2;
+         type_vector = (struct type **)
+           xrealloc (type_vector,
+                     (type_vector_length * sizeof (struct type *)));
+         bzero (&type_vector[type_vector_length / 2],
+                type_vector_length * sizeof (struct type *) / 2);
+       }
+      return &type_vector[index];
+    }
+  else
+    {
+      register int real_filenum = this_object_header_files[filenum];
+      register struct header_file *f;
+      int f_orig_length;
+
+      if (real_filenum >= n_header_files)
+       abort ();
+
+      f = &header_files[real_filenum];
+
+      f_orig_length = f->length;
+      if (index >= f_orig_length)
+       {
+         while (index >= f->length)
+           f->length *= 2;
+         f->vector = (struct type **)
+           xrealloc (f->vector, f->length * sizeof (struct type *));
+         bzero (&f->vector[f_orig_length],
+                (f->length - f_orig_length) * sizeof (struct type *));
+       }
+      return &f->vector[index];
+    }
+}
+
+/* Create a type object.  Occaisionally used when you need a type
+   which isn't going to be given a type number.  */
+
+struct type *
+dbx_create_type ()
+{
+  register struct type *type =
+    (struct type *) obstack_alloc (symbol_obstack, sizeof (struct type));
+
+  bzero (type, sizeof (struct type));
+  TYPE_VPTR_FIELDNO (type) = -1;
+  TYPE_VPTR_BASETYPE (type) = 0;
+  return type;
+}
+
+/* Make sure there is a type allocated for type numbers TYPENUMS
+   and return the type object.
+   This can create an empty (zeroed) type object.
+   TYPENUMS may be (-1, -1) to return a new type object that is not
+   put into the type vector, and so may not be referred to by number. */
+
+struct type *
+dbx_alloc_type (typenums)
+     int typenums[2];
+{
+  register struct type **type_addr;
+  register struct type *type;
+
+  if (typenums[1] != -1)
+    {
+      type_addr = dbx_lookup_type (typenums);
+      type = *type_addr;
+    }
+  else
+    {
+      type_addr = 0;
+      type = 0;
+    }
+
+  /* If we are referring to a type not known at all yet,
+     allocate an empty type for it.
+     We will fill it in later if we find out how.  */
+  if (type == 0)
+    {
+      type = dbx_create_type ();
+      if (type_addr)
+       *type_addr = type;
+    }
+  
+  return type;
+}
+\f
+/* maintain the lists of symbols and blocks */
+
+/* Add a symbol to one of the lists of symbols.  */
+void
+add_symbol_to_list (symbol, listhead)
+     struct symbol *symbol;
+     struct pending **listhead;
+{
+  /* We keep PENDINGSIZE symbols in each link of the list.
+     If we don't have a link with room in it, add a new link.  */
+  if (*listhead == 0 || (*listhead)->nsyms == PENDINGSIZE)
+    {
+      register struct pending *link;
+      if (free_pendings)
+       {
+         link = free_pendings;
+         free_pendings = link->next;
+       }
+      else
+       link = (struct pending *) xmalloc (sizeof (struct pending));
+
+      link->next = *listhead;
+      *listhead = link;
+      link->nsyms = 0;
+    }
+
+  (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
+}
+
+/* At end of reading syms, or in case of quit,
+   really free as many `struct pending's as we can easily find.  */
+
+/* ARGSUSED */
+void
+really_free_pendings (foo)
+     int foo;
+{
+  struct pending *next, *next1;
+#if 0
+  struct pending_block *bnext, *bnext1;
+#endif
+
+  for (next = free_pendings; next; next = next1)
+    {
+      next1 = next->next;
+      free (next);
+    }
+  free_pendings = 0;
+
+#if 0 /* Now we make the links in the symbol_obstack, so don't free them.  */
+  for (bnext = pending_blocks; bnext; bnext = bnext1)
+    {
+      bnext1 = bnext->next;
+      free (bnext);
+    }
+#endif
+  pending_blocks = 0;
+
+  for (next = file_symbols; next; next = next1)
+    {
+      next1 = next->next;
+      free (next);
+    }
+  file_symbols = 0;
+
+  for (next = global_symbols; next; next = next1)
+    {
+      next1 = next->next;
+      free (next);
+    }
+  global_symbols = 0;
+}
+
+/* Take one of the lists of symbols and make a block from it.
+   Keep the order the symbols have in the list (reversed from the input file).
+   Put the block on the list of pending blocks.  */
+
+void
+finish_block (symbol, listhead, old_blocks, start, end)
+     struct symbol *symbol;
+     struct pending **listhead;
+     struct pending_block *old_blocks;
+     CORE_ADDR start, end;
+{
+  register struct pending *next, *next1;
+  register struct block *block;
+  register struct pending_block *pblock;
+  struct pending_block *opblock;
+  register int i;
+
+  /* Count the length of the list of symbols.  */
+
+  for (next = *listhead, i = 0; next; i += next->nsyms, next = next->next)
+    /*EMPTY*/;
+
+  block = (struct block *) obstack_alloc (symbol_obstack,
+                                         (sizeof (struct block)
+                                          + ((i - 1)
+                                             * sizeof (struct symbol *))));
+
+  /* Copy the symbols into the block.  */
+
+  BLOCK_NSYMS (block) = i;
+  for (next = *listhead; next; next = next->next)
+    {
+      register int j;
+      for (j = next->nsyms - 1; j >= 0; j--)
+       BLOCK_SYM (block, --i) = next->symbol[j];
+    }
+
+  BLOCK_START (block) = start;
+  BLOCK_END (block) = end;
+  BLOCK_SUPERBLOCK (block) = 0;        /* Filled in when containing block is made */
+  BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
+
+  /* Put the block in as the value of the symbol that names it.  */
+
+  if (symbol)
+    {
+      SYMBOL_BLOCK_VALUE (symbol) = block;
+      BLOCK_FUNCTION (block) = symbol;
+    }
+  else
+    BLOCK_FUNCTION (block) = 0;
+
+  /* Now "free" the links of the list, and empty the list.  */
+
+  for (next = *listhead; next; next = next1)
+    {
+      next1 = next->next;
+      next->next = free_pendings;
+      free_pendings = next;
+    }
+  *listhead = 0;
+
+  /* Install this block as the superblock
+     of all blocks made since the start of this scope
+     that don't have superblocks yet.  */
+
+  opblock = 0;
+  for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
+    {
+      if (BLOCK_SUPERBLOCK (pblock->block) == 0) {
+#if 1
+       /* Check to be sure the blocks are nested as we receive them. 
+          If the compiler/assembler/linker work, this just burns a small
+          amount of time.  */
+       if (BLOCK_START (pblock->block) < BLOCK_START (block)
+        || BLOCK_END   (pblock->block) > BLOCK_END   (block)) {
+         complain(&innerblock_complaint, symbol? SYMBOL_NAME (symbol):
+                                                "(don't know)");
+         BLOCK_START (pblock->block) = BLOCK_START (block);
+         BLOCK_END   (pblock->block) = BLOCK_END   (block);
+       }
+#endif
+       BLOCK_SUPERBLOCK (pblock->block) = block;
+      }
+      opblock = pblock;
+    }
+
+  /* Record this block on the list of all blocks in the file.
+     Put it after opblock, or at the beginning if opblock is 0.
+     This puts the block in the list after all its subblocks.  */
+
+  /* Allocate in the symbol_obstack to save time.
+     It wastes a little space.  */
+  pblock = (struct pending_block *)
+    obstack_alloc (symbol_obstack,
+                  sizeof (struct pending_block));
+  pblock->block = block;
+  if (opblock)
+    {
+      pblock->next = opblock->next;
+      opblock->next = pblock;
+    }
+  else
+    {
+      pblock->next = pending_blocks;
+      pending_blocks = pblock;
+    }
+}
+
+struct blockvector *
+make_blockvector ()
+{
+  register struct pending_block *next;
+  register struct blockvector *blockvector;
+  register int i;
+
+  /* Count the length of the list of blocks.  */
+
+  for (next = pending_blocks, i = 0; next; next = next->next, i++);
+
+  blockvector = (struct blockvector *)
+    obstack_alloc (symbol_obstack,
+                  (sizeof (struct blockvector)
+                   + (i - 1) * sizeof (struct block *)));
+
+  /* Copy the blocks into the blockvector.
+     This is done in reverse order, which happens to put
+     the blocks into the proper order (ascending starting address).
+     finish_block has hair to insert each block into the list
+     after its subblocks in order to make sure this is true.  */
+
+  BLOCKVECTOR_NBLOCKS (blockvector) = i;
+  for (next = pending_blocks; next; next = next->next) {
+    BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
+  }
+
+#if 0 /* Now we make the links in the obstack, so don't free them.  */
+  /* Now free the links of the list, and empty the list.  */
+
+  for (next = pending_blocks; next; next = next1)
+    {
+      next1 = next->next;
+      free (next);
+    }
+#endif
+  pending_blocks = 0;
+
+#if 1  /* FIXME, shut this off after a while to speed up symbol reading.  */
+  /* Some compilers output blocks in the wrong order, but we depend
+     on their being in the right order so we can binary search. 
+     Check the order and moan about it.  FIXME.  */
+  if (BLOCKVECTOR_NBLOCKS (blockvector) > 1)
+    for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++) {
+      if (BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i-1))
+         > BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i))) {
+       complain (&blockvector_complaint, 
+         BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i)));
+      }
+    }
+#endif
+
+  return blockvector;
+}
+\f
+/* Manage the vector of line numbers.  */
+
+void
+record_line (line, pc)
+     int line;
+     CORE_ADDR pc;
+{
+  struct linetable_entry *e;
+  /* Ignore the dummy line number in libg.o */
+
+  if (line == 0xffff)
+    return;
+
+  /* Make sure line vector is big enough.  */
+
+  if (line_vector_index + 1 >= line_vector_length)
+    {
+      line_vector_length *= 2;
+      line_vector = (struct linetable *)
+       xrealloc (line_vector,
+                 (sizeof (struct linetable)
+                  + line_vector_length * sizeof (struct linetable_entry)));
+      current_subfile->line_vector = line_vector;
+    }
+
+  e = line_vector->item + line_vector_index++;
+  e->line = line; e->pc = pc;
+}
+\f
+/* Start a new symtab for a new source file.
+   This is called when a dbx symbol of type N_SO is seen;
+   it indicates the start of data for one original source file.  */
+
+void
+start_symtab (name, dirname, start_addr)
+     char *name;
+     char *dirname;
+     CORE_ADDR start_addr;
+{
+
+  last_source_file = name;
+  last_source_start_addr = start_addr;
+  file_symbols = 0;
+  global_symbols = 0;
+  within_function = 0;
+
+  /* Context stack is initially empty, with room for 10 levels.  */
+  context_stack
+    = (struct context_stack *) xmalloc (10 * sizeof (struct context_stack));
+  context_stack_size = 10;
+  context_stack_depth = 0;
+
+  new_object_header_files ();
+
+  type_vector_length = 160;
+  type_vector = (struct type **)
+    xmalloc (type_vector_length * sizeof (struct type *));
+  bzero (type_vector, type_vector_length * sizeof (struct type *));
+
+  /* Initialize the list of sub source files with one entry
+     for this file (the top-level source file).  */
+
+  subfiles = 0;
+  current_subfile = 0;
+  start_subfile (name, dirname);
+}
+
+/* Finish the symbol definitions for one main source file,
+   close off all the lexical contexts for that file
+   (creating struct block's for them), then make the struct symtab
+   for that file and put it in the list of all such.
+
+   END_ADDR is the address of the end of the file's text.  */
+
+struct symtab *
+end_symtab (end_addr)
+     CORE_ADDR end_addr;
+{
+  register struct symtab *symtab;
+  register struct blockvector *blockvector;
+  register struct subfile *subfile;
+  register struct linetable *lv;
+  struct subfile *nextsub;
+
+  /* Finish the lexical context of the last function in the file;
+     pop the context stack.  */
+
+  if (context_stack_depth > 0)
+    {
+      register struct context_stack *cstk;
+      context_stack_depth--;
+      cstk = &context_stack[context_stack_depth];
+      /* Make a block for the local symbols within.  */
+      finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+                   cstk->start_addr, end_addr);
+    }
+
+  /* Cleanup any undefined types that have been left hanging around
+     (this needs to be done before the finish_blocks so that
+     file_symbols is still good).  */
+  cleanup_undefined_types ();
+
+  /* Define the STATIC_BLOCK and GLOBAL_BLOCK, and build the blockvector.  */
+  finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr);
+  finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr);
+  blockvector = make_blockvector ();
+
+  current_subfile->line_vector_index = line_vector_index;
+
+  /* Now create the symtab objects proper, one for each subfile.  */
+  /* (The main file is the last one on the chain.)  */
+
+  for (subfile = subfiles; subfile; subfile = nextsub)
+    {
+      symtab = allocate_symtab (subfile->name);
+
+      /* Fill in its components.  */
+      symtab->blockvector = blockvector;
+      lv = subfile->line_vector;
+      lv->nitems = subfile->line_vector_index;
+      symtab->linetable = (struct linetable *)
+       xrealloc (lv, (sizeof (struct linetable)
+                      + lv->nitems * sizeof (struct linetable_entry)));
+
+      symtab->dirname = subfile->dirname;
+
+      symtab->free_code = free_linetable;
+      symtab->free_ptr = 0;
+
+      /* There should never already be a symtab for this name, since
+        any prev dups have been removed when the psymtab was read in.
+        FIXME, there ought to be a way to check this here.  */
+      /* FIXME blewit |= free_named_symtabs (symtab->filename);  */
+
+      /* Link the new symtab into the list of such.  */
+      symtab->next = symtab_list;
+      symtab_list = symtab;
+
+      nextsub = subfile->next;
+      free (subfile);
+    }
+
+  free ((char *) type_vector);
+  type_vector = 0;
+  type_vector_length = -1;
+  line_vector = 0;
+  line_vector_length = -1;
+  last_source_file = 0;
+
+  return symtab;
+}
+\f
+/* Initialize anything that needs initializing when starting to read
+   a fresh piece of a symbol file, e.g. reading in the stuff corresponding
+   to a psymtab.  */
+
+void
+buildsym_init ()
+{
+  free_pendings = 0;
+  file_symbols = 0;
+  global_symbols = 0;
+  pending_blocks = 0;
+}
+
+/* Initialize anything that needs initializing when a completely new
+   symbol file is specified (not just adding some symbols from another
+   file, e.g. a shared library).  */
+
+void
+buildsym_new_init ()
+{
+  /* Empty the hash table of global syms looking for values.  */
+  bzero (global_sym_chain, sizeof global_sym_chain);
+
+  buildsym_init ();
+}
+
+/* Scan through all of the global symbols defined in the object file,
+   assigning values to the debugging symbols that need to be assigned
+   to.  Get these symbols from the misc function list.  */
+
+void
+scan_file_globals ()
+{
+  int hash;
+  int mf;
+
+  for (mf = 0; mf < misc_function_count; mf++)
+    {
+      char *namestring = misc_function_vector[mf].name;
+      struct symbol *sym, *prev;
+
+      QUIT;
+
+      prev = (struct symbol *) 0;
+
+      /* Get the hash index and check all the symbols
+        under that hash index. */
+
+      hash = hashname (namestring);
+
+      for (sym = global_sym_chain[hash]; sym;)
+       {
+         if (*namestring == SYMBOL_NAME (sym)[0]
+             && !strcmp(namestring + 1, SYMBOL_NAME (sym) + 1))
+           {
+             /* Splice this symbol out of the hash chain and
+                assign the value we have to it. */
+             if (prev)
+               SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym);
+             else
+               global_sym_chain[hash] = SYMBOL_VALUE_CHAIN (sym);
+             
+             /* Check to see whether we need to fix up a common block.  */
+             /* Note: this code might be executed several times for
+                the same symbol if there are multiple references.  */
+             if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+               fix_common_block (sym, misc_function_vector[mf].address);
+             else
+               SYMBOL_VALUE_ADDRESS (sym) = misc_function_vector[mf].address;
+             
+             if (prev)
+               sym = SYMBOL_VALUE_CHAIN (prev);
+             else
+               sym = global_sym_chain[hash];
+           }
+         else
+           {
+             prev = sym;
+             sym = SYMBOL_VALUE_CHAIN (sym);
+           }
+       }
+    }
+}
+
+\f
+/* Read a number by which a type is referred to in dbx data,
+   or perhaps read a pair (FILENUM, TYPENUM) in parentheses.
+   Just a single number N is equivalent to (0,N).
+   Return the two numbers by storing them in the vector TYPENUMS.
+   TYPENUMS will then be used as an argument to dbx_lookup_type.  */
+
+void
+read_type_number (pp, typenums)
+     register char **pp;
+     register int *typenums;
+{
+  if (**pp == '(')
+    {
+      (*pp)++;
+      typenums[0] = read_number (pp, ',');
+      typenums[1] = read_number (pp, ')');
+    }
+  else
+    {
+      typenums[0] = 0;
+      typenums[1] = read_number (pp, 0);
+    }
+}
+\f
+/* To handle GNU C++ typename abbreviation, we need to be able to
+   fill in a type's name as soon as space for that type is allocated.
+   `type_synonym_name' is the name of the type being allocated.
+   It is cleared as soon as it is used (lest all allocated types
+   get this name).  */
+static char *type_synonym_name;
+
+/* ARGSUSED */
+static struct symbol *
+define_symbol (valu, string, desc, type)
+     unsigned int valu;
+     char *string;
+     int desc;
+     int type;
+{
+  register struct symbol *sym;
+  char *p = (char *) strchr (string, ':');
+  int deftype;
+  int synonym = 0;
+  register int i;
+
+  /* Ignore syms with empty names.  */
+  if (string[0] == 0)
+    return 0;
+
+  /* Ignore old-style symbols from cc -go  */
+  if (p == 0)
+    return 0;
+
+  sym = (struct symbol *)obstack_alloc (symbol_obstack, sizeof (struct symbol));
+
+  if (processing_gcc_compilation) {
+    /* GCC 2.x puts the line number in desc.  SunOS apparently puts in the
+       number of bytes occupied by a type or object, which we ignore.  */
+    SYMBOL_LINE(sym) = desc;
+  } else {
+    SYMBOL_LINE(sym) = 0;                      /* unknown */
+  }
+
+  if (string[0] == CPLUS_MARKER)
+    {
+      /* Special GNU C++ names.  */
+      switch (string[1])
+       {
+       case 't':
+         SYMBOL_NAME (sym) = "this";
+         break;
+       case 'v': /* $vtbl_ptr_type */
+         /* Was: SYMBOL_NAME (sym) = "vptr"; */
+         goto normal;
+       case 'e':
+         SYMBOL_NAME (sym) = "eh_throw";
+         break;
+
+       case '_':
+         /* This was an anonymous type that was never fixed up.  */
+         goto normal;
+
+       default:
+         abort ();
+       }
+    }
+  else
+    {
+    normal:
+      SYMBOL_NAME (sym)
+       = (char *) obstack_alloc (symbol_obstack, ((p - string) + 1));
+      /* Open-coded bcopy--saves function call time.  */
+      {
+       register char *p1 = string;
+       register char *p2 = SYMBOL_NAME (sym);
+       while (p1 != p)
+         *p2++ = *p1++;
+       *p2++ = '\0';
+      }
+    }
+  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...' . 
+     (gnu@cygnus.com) -- this strchr() handles them properly?
+     (tiemann@cygnus.com) -- 'C' is for catch.  */
+  if (!strchr ("cfFGpPrStTvVXC", *p))
+    deftype = 'l';
+  else
+    deftype = *p++;
+
+  /* c is a special case, not followed by a type-number.
+     SYMBOL:c=iVALUE for an integer constant symbol.
+     SYMBOL:c=rVALUE for a floating constant symbol.
+     SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+        e.g. "b:c=e6,0" for "const b = blob1"
+       (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
+  if (deftype == 'c')
+    {
+      if (*p++ != '=')
+       error ("Invalid symbol data at symtab pos %d.", symnum);
+      switch (*p++)
+       {
+       case 'r':
+         {
+           double d = atof (p);
+           char *dbl_valu;
+
+           SYMBOL_TYPE (sym) = builtin_type_double;
+           dbl_valu =
+             (char *) obstack_alloc (symbol_obstack, sizeof (double));
+           bcopy (&d, dbl_valu, sizeof (double));
+           SWAP_TARGET_AND_HOST (dbl_valu, sizeof (double));
+           SYMBOL_VALUE_BYTES (sym) = dbl_valu;
+           SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+         }
+         break;
+       case 'i':
+         {
+           SYMBOL_TYPE (sym) = builtin_type_int;
+           SYMBOL_VALUE (sym) = atoi (p);
+           SYMBOL_CLASS (sym) = LOC_CONST;
+         }
+         break;
+       case 'e':
+         /* SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+            e.g. "b:c=e6,0" for "const b = blob1"
+            (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
+         {
+           int typenums[2];
+           
+           read_type_number (&p, typenums);
+           if (*p++ != ',')
+             error ("Invalid symbol data: no comma in enum const symbol");
+           
+           SYMBOL_TYPE (sym) = *dbx_lookup_type (typenums);
+           SYMBOL_VALUE (sym) = atoi (p);
+           SYMBOL_CLASS (sym) = LOC_CONST;
+         }
+         break;
+       default:
+         error ("Invalid symbol data at symtab pos %d.", symnum);
+       }
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      return sym;
+    }
+
+  /* Now usually comes a number that says which data type,
+     and possibly more stuff to define the type
+     (all of which is handled by read_type)  */
+
+  if (deftype == 'p' && *p == 'F')
+    /* pF is a two-letter code that means a function parameter in Fortran.
+       The type-number specifies the type of the return value.
+       Translate it into a pointer-to-function type.  */
+    {
+      p++;
+      SYMBOL_TYPE (sym)
+       = lookup_pointer_type (lookup_function_type (read_type (&p)));
+    }
+  else
+    {
+      struct type *type_read;
+      synonym = *p == 't';
+
+      if (synonym)
+       {
+         p += 1;
+         type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+                                           strlen (SYMBOL_NAME (sym)));
+       }
+
+      type_read = read_type (&p);
+
+      if ((deftype == 'F' || deftype == 'f')
+         && TYPE_CODE (type_read) != TYPE_CODE_FUNC)
+      {
+#if 0
+/* This code doesn't work -- it needs to realloc and can't.  */
+       struct type *new = (struct type *)
+             obstack_alloc (symbol_obstack, sizeof (struct type));
+
+       /* Generate a template for the type of this function.  The 
+          types of the arguments will be added as we read the symbol 
+          table. */
+       *new = *lookup_function_type (type_read);
+       SYMBOL_TYPE(sym) = new;
+       in_function_type = new;
+#else
+       SYMBOL_TYPE (sym) = lookup_function_type (type_read);
+#endif
+      }
+      else
+       SYMBOL_TYPE (sym) = type_read;
+    }
+
+  switch (deftype)
+    {
+    case 'C':
+      /* The name of a caught exception.  */
+      SYMBOL_CLASS (sym) = LOC_LABEL;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'f':
+      SYMBOL_CLASS (sym) = LOC_BLOCK;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    case 'F':
+      SYMBOL_CLASS (sym) = LOC_BLOCK;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &global_symbols);
+      break;
+
+    case 'G':
+      /* For a class G (global) symbol, it appears that the
+        value is not correct.  It is necessary to search for the
+        corresponding linker definition to find the value.
+        These definitions appear at the end of the namelist.  */
+      i = hashname (SYMBOL_NAME (sym));
+      SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+      global_sym_chain[i] = sym;
+      SYMBOL_CLASS (sym) = LOC_STATIC;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &global_symbols);
+      break;
+
+      /* This case is faked by a conditional above,
+        when there is no code letter in the dbx data.
+        Dbx data never actually contains 'l'.  */
+    case 'l':
+      SYMBOL_CLASS (sym) = LOC_LOCAL;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'p':
+      /* Normally this is a parameter, a LOC_ARG.  On the i960, it
+        can also be a LOC_LOCAL_ARG depending on symbol type.  */
+#ifndef DBX_PARM_SYMBOL_CLASS
+#define        DBX_PARM_SYMBOL_CLASS(type)     LOC_ARG
+#endif
+      SYMBOL_CLASS (sym) = DBX_PARM_SYMBOL_CLASS (type);
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+#if 0
+      /* This doesn't work yet.  */
+      add_param_to_type (&in_function_type, sym);
+#endif
+      add_symbol_to_list (sym, &local_symbols);
+
+      /* If it's gcc-compiled, if it says `short', believe it.  */
+      if (processing_gcc_compilation || BELIEVE_PCC_PROMOTION)
+       break;
+
+#if defined(BELIEVE_PCC_PROMOTION_TYPE)
+      /* This macro is defined on machines (e.g. sparc) where
+        we should believe the type of a PCC 'short' argument,
+        but shouldn't believe the address (the address is
+        the address of the corresponding int).  Note that
+        this is only different from the BELIEVE_PCC_PROMOTION
+        case on big-endian machines.
+
+        My guess is that this correction, as opposed to changing
+        the parameter to an 'int' (as done below, for PCC
+        on most machines), is the right thing to do
+        on all machines, but I don't want to risk breaking
+        something that already works.  On most PCC machines,
+        the sparc problem doesn't come up because the calling
+        function has to zero the top bytes (not knowing whether
+        the called function wants an int or a short), so there
+        is no practical difference between an int and a short
+        (except perhaps what happens when the GDB user types
+        "print short_arg = 0x10000;"). 
+
+        Hacked for SunOS 4.1 by gnu@cygnus.com.  In 4.1, the compiler
+        actually produces the correct address (we don't need to fix it
+        up).  I made this code adapt so that it will offset the symbol
+        if it was pointing at an int-aligned location and not
+        otherwise.  This way you can use the same gdb for 4.0.x and
+        4.1 systems.  */
+
+      if (0 == SYMBOL_VALUE (sym) % sizeof (int))
+       {
+         if (SYMBOL_TYPE (sym) == builtin_type_char
+             || SYMBOL_TYPE (sym) == builtin_type_unsigned_char)
+           SYMBOL_VALUE (sym) += 3;
+         else if (SYMBOL_TYPE (sym) == builtin_type_short
+             || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+           SYMBOL_VALUE (sym) += 2;
+       }
+      break;
+
+#else /* no BELIEVE_PCC_PROMOTION_TYPE.  */
+
+      /* If PCC says a parameter is a short or a char,
+        it is really an int.  */
+      if (SYMBOL_TYPE (sym) == builtin_type_char
+         || SYMBOL_TYPE (sym) == builtin_type_short)
+       SYMBOL_TYPE (sym) = builtin_type_int;
+      else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char
+              || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+       SYMBOL_TYPE (sym) = builtin_type_unsigned_int;
+      break;
+
+#endif /* no BELIEVE_PCC_PROMOTION_TYPE.  */
+
+    case 'P':
+      SYMBOL_CLASS (sym) = LOC_REGPARM;
+      SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'r':
+      SYMBOL_CLASS (sym) = LOC_REGISTER;
+      SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'S':
+      /* Static symbol at top level of file */
+      SYMBOL_CLASS (sym) = LOC_STATIC;
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    case 't':
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+         && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+       TYPE_NAME (SYMBOL_TYPE (sym)) =
+         obsavestring (SYMBOL_NAME (sym),
+                       strlen (SYMBOL_NAME (sym)));
+       /* C++ vagaries: we may have a type which is derived from
+        a base type which did not have its name defined when the
+        derived class was output.  We fill in the derived class's
+        base part member's name here in that case.  */
+       else if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+                || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)
+               && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)))
+        {
+          int j;
+          for (j = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)) - 1; j >= 0; j--)
+            if (TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) == 0)
+              TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) =
+                type_name_no_tag (TYPE_BASECLASS (SYMBOL_TYPE (sym), j));
+        }
+
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    case 'T':
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+      if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+         && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+       TYPE_NAME (SYMBOL_TYPE (sym))
+         = obconcat ("",
+                     (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM
+                      ? "enum "
+                      : (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+                         ? "struct " : "union ")),
+                     SYMBOL_NAME (sym));
+      add_symbol_to_list (sym, &file_symbols);
+
+      if (synonym)
+       {
+         register struct symbol *typedef_sym
+           = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+         SYMBOL_NAME (typedef_sym) = SYMBOL_NAME (sym);
+         SYMBOL_TYPE (typedef_sym) = SYMBOL_TYPE (sym);
+
+         SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF;
+         SYMBOL_VALUE (typedef_sym) = valu;
+         SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE;
+         add_symbol_to_list (typedef_sym, &file_symbols);
+       }
+      break;
+
+    case 'V':
+      /* Static symbol of local scope */
+      SYMBOL_CLASS (sym) = LOC_STATIC;
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'v':
+      /* Reference parameter */
+      SYMBOL_CLASS (sym) = LOC_REF_ARG;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'X':
+      /* This is used by Sun FORTRAN for "function result value".
+        Sun claims ("dbx and dbxtool interfaces", 2nd ed)
+        that Pascal uses it too, but when I tried it Pascal used
+        "x:3" (local symbol) instead.  */
+      SYMBOL_CLASS (sym) = LOC_LOCAL;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    default:
+      error ("Invalid symbol data: unknown symbol-type code `%c' at symtab pos %d.", deftype, symnum);
+    }
+  return sym;
+}
+\f
+/* What about types defined as forward references inside of a small lexical
+   scope?  */
+/* Add a type to the list of undefined types to be checked through
+   once this file has been read in.  */
+static void
+add_undefined_type (type)
+     struct type *type;
+{
+  if (undef_types_length == undef_types_allocated)
+    {
+      undef_types_allocated *= 2;
+      undef_types = (struct type **)
+       xrealloc (undef_types,
+                 undef_types_allocated * sizeof (struct type *));
+    }
+  undef_types[undef_types_length++] = type;
+}
+
+/* Add here something to go through each undefined type, see if it's
+   still undefined, and do a full lookup if so.  */
+static void
+cleanup_undefined_types ()
+{
+  struct type **type;
+
+  for (type = undef_types; type < undef_types + undef_types_length; type++)
+    {
+      /* Reasonable test to see if it's been defined since.  */
+      if (TYPE_NFIELDS (*type) == 0)
+       {
+         struct pending *ppt;
+         int i;
+         /* Name of the type, without "struct" or "union" */
+         char *typename = TYPE_NAME (*type);
+
+         if (!strncmp (typename, "struct ", 7))
+           typename += 7;
+         if (!strncmp (typename, "union ", 6))
+           typename += 6;
+
+         for (ppt = file_symbols; ppt; ppt = ppt->next)
+           for (i = 0; i < ppt->nsyms; i++)
+             {
+               struct symbol *sym = ppt->symbol[i];
+
+               if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+                   && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+                   && (TYPE_CODE (SYMBOL_TYPE (sym)) ==
+                       TYPE_CODE (*type))
+                   && !strcmp (SYMBOL_NAME (sym), typename))
+                 bcopy (SYMBOL_TYPE (sym), *type, sizeof (struct type));
+             }
+       }
+      else
+       /* It has been defined; don't mark it as a stub.  */
+       TYPE_FLAGS (*type) &= ~TYPE_FLAG_STUB;
+    }
+  undef_types_length = 0;
+}
+\f
+/* Skip rest of this symbol and return an error type.
+
+   General notes on error recovery:  error_type always skips to the
+   end of the symbol (modulo cretinous dbx symbol name continuation).
+   Thus code like this:
+
+   if (*(*pp)++ != ';')
+     return error_type (pp);
+
+   is wrong because if *pp starts out pointing at '\0' (typically as the
+   result of an earlier error), it will be incremented to point to the
+   start of the next symbol, which might produce strange results, at least
+   if you run off the end of the string table.  Instead use
+
+   if (**pp != ';')
+     return error_type (pp);
+   ++*pp;
+
+   or
+
+   if (**pp != ';')
+     foo = error_type (pp);
+   else
+     ++*pp;
+
+   And in case it isn't obvious, the point of all this hair is so the compiler
+   can define new types and new syntaxes, and old versions of the
+   debugger will be able to read the new symbol tables.  */
+
+struct type *
+error_type (pp)
+     char **pp;
+{
+  complain (&error_type_complaint, 0);
+  while (1)
+    {
+      /* Skip to end of symbol.  */
+      while (**pp != '\0')
+       (*pp)++;
+
+      /* Check for and handle cretinous dbx symbol name continuation!  */
+      if ((*pp)[-1] == '\\')
+       *pp = next_symbol_text ();
+      else
+       break;
+    }
+  return builtin_type_error;
+}
+\f
+/* Read a dbx type reference or definition;
+   return the type that is meant.
+   This can be just a number, in which case it references
+   a type already defined and placed in type_vector.
+   Or the number can be followed by an =, in which case
+   it means to define a new type according to the text that
+   follows the =.  */
+
+struct type *
+read_type (pp)
+     register char **pp;
+{
+  register struct type *type = 0;
+  struct type *type1;
+  int typenums[2];
+  int xtypenums[2];
+
+  /* Read type number if present.  The type number may be omitted.
+     for instance in a two-dimensional array declared with type
+     "ar1;1;10;ar1;1;10;4".  */
+  if ((**pp >= '0' && **pp <= '9')
+      || **pp == '(')
+    {
+      read_type_number (pp, typenums);
+      
+      /* Detect random reference to type not yet defined.
+        Allocate a type object but leave it zeroed.  */
+      if (**pp != '=')
+       return dbx_alloc_type (typenums);
+
+      *pp += 2;
+    }
+  else
+    {
+      /* '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;
+    }
+      
+  switch ((*pp)[-1])
+    {
+    case 'x':
+      {
+       enum type_code code;
+
+       /* Used to index through file_symbols.  */
+       struct pending *ppt;
+       int i;
+       
+       /* Name including "struct", etc.  */
+       char *type_name;
+       
+       /* Name without "struct", etc.  */
+       char *type_name_only;
+
+       {
+         char *prefix;
+         char *from, *to;
+         
+         /* Set the type code according to the following letter.  */
+         switch ((*pp)[0])
+           {
+           case 's':
+             code = TYPE_CODE_STRUCT;
+             prefix = "struct ";
+             break;
+           case 'u':
+             code = TYPE_CODE_UNION;
+             prefix = "union ";
+             break;
+           case 'e':
+             code = TYPE_CODE_ENUM;
+             prefix = "enum ";
+             break;
+           default:
+             return error_type (pp);
+           }
+         
+         to = type_name = (char *)
+           obstack_alloc (symbol_obstack,
+                          (strlen (prefix) +
+                           ((char *) strchr (*pp, ':') - (*pp)) + 1));
+       
+         /* Copy the prefix.  */
+         from = prefix;
+         while (*to++ = *from++)
+           ;
+         to--; 
+       
+         type_name_only = to;
+
+         /* Copy the name.  */
+         from = *pp + 1;
+         while ((*to++ = *from++) != ':')
+           ;
+         *--to = '\0';
+         
+         /* Set the pointer ahead of the name which we just read.  */
+         *pp = from;
+       
+#if 0
+         /* The following hack is clearly wrong, because it doesn't
+            check whether we are in a baseclass.  I tried to reproduce
+            the case that it is trying to fix, but I couldn't get
+            g++ to put out a cross reference to a basetype.  Perhaps
+            it doesn't do it anymore.  */
+         /* Note: for C++, the cross reference may be to a base type which
+            has not yet been seen.  In this case, we skip to the comma,
+            which will mark the end of the base class name.  (The ':'
+            at the end of the base class name will be skipped as well.)
+            But sometimes (ie. when the cross ref is the last thing on
+            the line) there will be no ','.  */
+         from = (char *) strchr (*pp, ',');
+         if (from)
+           *pp = from;
+#endif /* 0 */
+       }
+
+       /* Now check to see whether the type has already been declared.  */
+       /* This is necessary at least in the case where the
+          program says something like
+            struct foo bar[5];
+          The compiler puts out a cross-reference; we better find
+          set the length of the structure correctly so we can
+          set the length of the array.  */
+       for (ppt = file_symbols; ppt; ppt = ppt->next)
+         for (i = 0; i < ppt->nsyms; i++)
+           {
+             struct symbol *sym = ppt->symbol[i];
+
+             if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+                 && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+                 && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
+                 && !strcmp (SYMBOL_NAME (sym), type_name_only))
+               {
+                 obstack_free (symbol_obstack, type_name);
+                 type = SYMBOL_TYPE (sym);
+                 return type;
+               }
+           }
+       
+       /* Didn't find the type to which this refers, so we must
+          be dealing with a forward reference.  Allocate a type
+          structure for it, and keep track of it so we can
+          fill in the rest of the fields when we get the full
+          type.  */
+       type = dbx_alloc_type (typenums);
+       TYPE_CODE (type) = code;
+       TYPE_NAME (type) = type_name;
+
+       TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+
+       add_undefined_type (type);
+       return type;
+      }
+
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '(':
+      (*pp)--;
+      read_type_number (pp, xtypenums);
+      type = *dbx_lookup_type (xtypenums);
+      if (type == 0)
+       type = builtin_type_void;
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case '*':
+      type1 = read_type (pp);
+      type = lookup_pointer_type (type1);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case '@':
+      {
+       struct type *domain = read_type (pp);
+       struct type *memtype;
+
+       if (**pp != ',')
+         /* Invalid member type data format.  */
+         return error_type (pp);
+       ++*pp;
+
+       memtype = read_type (pp);
+       type = dbx_alloc_type (typenums);
+       smash_to_member_type (type, domain, memtype);
+      }
+      break;
+
+    case '#':
+      if ((*pp)[0] == '#')
+       {
+         /* We'll get the parameter types from the name.  */
+         struct type *return_type;
+
+         *pp += 1;
+         return_type = read_type (pp);
+         if (*(*pp)++ != ';')
+           complain (&invalid_member_complaint, symnum);
+         type = allocate_stub_method (return_type);
+         if (typenums[0] != -1)
+           *dbx_lookup_type (typenums) = type;
+       }
+      else
+       {
+         struct type *domain = read_type (pp);
+         struct type *return_type;
+         struct type **args;
+
+         if (*(*pp)++ != ',')
+           error ("invalid member type data format, at symtab pos %d.",
+                  symnum);
+
+         return_type = read_type (pp);
+         args = read_args (pp, ';');
+         type = dbx_alloc_type (typenums);
+         smash_to_method_type (type, domain, return_type, args);
+       }
+      break;
+
+    case '&':
+      type1 = read_type (pp);
+      type = lookup_reference_type (type1);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 'f':
+      type1 = read_type (pp);
+      type = lookup_function_type (type1);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 'r':
+      type = read_range_type (pp, typenums);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 'e':
+      type = dbx_alloc_type (typenums);
+      type = read_enum_type (pp, type);
+      *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 's':
+      type = dbx_alloc_type (typenums);
+      TYPE_NAME (type) = type_synonym_name;
+      type_synonym_name = 0;
+      type = read_struct_type (pp, type);
+      break;
+
+    case 'u':
+      type = dbx_alloc_type (typenums);
+      TYPE_NAME (type) = type_synonym_name;
+      type_synonym_name = 0;
+      type = read_struct_type (pp, type);
+      TYPE_CODE (type) = TYPE_CODE_UNION;
+      break;
+
+    case 'a':
+      if (**pp != 'r')
+       return error_type (pp);
+      ++*pp;
+      
+      type = dbx_alloc_type (typenums);
+      type = read_array_type (pp, type);
+      break;
+
+    default:
+      --*pp;                   /* Go back to the symbol in error */
+                               /* Particularly important if it was \0! */
+      return error_type (pp);
+    }
+
+  if (type == 0)
+    abort ();
+
+#if 0
+  /* If this is an overriding temporary alteration for a header file's
+     contents, and this type number is unknown in the global definition,
+     put this type into the global definition at this type number.  */
+  if (header_file_prev_index >= 0)
+    {
+      register struct type **tp
+        = explicit_lookup_type (header_file_prev_index, typenums[1]);
+      if (*tp == 0)
+       *tp = type;
+    }
+#endif
+  return type;
+}
+\f
+/* This page contains subroutines of read_type.  */
+
+/* Read the description of a structure (or union type)
+   and return an object describing the type.  */
+
+struct type *
+read_struct_type (pp, type)
+     char **pp;
+     register struct type *type;
+{
+  /* 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 total_length = 0;
+
+  struct nextfield
+    {
+      struct nextfield *next;
+      int visibility;                  /* 0=public, 1=protected, 2=public */
+      struct field field;
+    };
+
+  struct next_fnfield
+    {
+      struct next_fnfield *next;
+      int visibility;                  /* 0=public, 1=protected, 2=public */
+      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;
+  register char *p;
+  int nfields = 0;
+  register int n;
+
+  register struct next_fnfieldlist *mainlist = 0;
+  int nfn_fields = 0;
+
+  if (TYPE_MAIN_VARIANT (type) == 0)
+    {
+      TYPE_MAIN_VARIANT (type) = type;
+    }
+
+  TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+  /* First comes the total size in bytes.  */
+
+  TYPE_LENGTH (type) = read_number (pp, 0);
+
+  /* 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 == '!')
+    {
+      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;
+
+      n_baseclasses = read_number (pp, ',');
+      TYPE_FIELD_VIRTUAL_BITS (type) =
+         (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (n_baseclasses));
+      B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), n_baseclasses);
+
+      for (i = 0; i < n_baseclasses; i++)
+       {
+         if (**pp == '\\')
+           *pp = next_symbol_text ();
+
+         switch (**pp)
+           {
+           case '0':
+             via_virtual = 0;
+             break;
+           case '1':
+             via_virtual = 1;
+             break;
+           default:
+             /* Bad visibility format.  */
+             return error_type (pp);
+           }
+         ++*pp;
+
+         switch (**pp)
+           {
+           case '0':
+             via_public = 0;
+             break;
+           case '2':
+             via_public = 2;
+             break;
+           default:
+             /* Bad visibility format.  */
+             return error_type (pp);
+           }
+         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);
+         *pp += 1;             /* skip trailing ';' */
+
+         /* Make this baseclass visible for structure-printing purposes.  */
+         new = (struct nextfield *) alloca (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++;
+       }
+      TYPE_N_BASECLASSES (type) = n_baseclasses;
+    }
+
+  /* Now come the fields, as NAME:?TYPENUM,BITPOS,BITSIZE; for each one.
+     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 `?' is a placeholder for one of '/2' (public visibility),
+     '/1' (protected visibility), '/0' (private visibility), or nothing
+     (C style symbol table, public visibility).  */
+
+  /* We better set p right now, in case there are no fields at all...    */
+  p = *pp;
+
+  while (**pp != ';')
+    {
+      /* Check for and handle cretinous dbx symbol name continuation!  */
+      if (**pp == '\\') *pp = next_symbol_text ();
+
+      /* Get space to record the next field's data.  */
+      new = (struct nextfield *) alloca (sizeof (struct nextfield));
+      new->next = list;
+      list = new;
+
+      /* Get the field name.  */
+      p = *pp;
+      if (*p == CPLUS_MARKER)
+       {
+         /* Special GNU C++ name.  */
+         if (*++p == 'v')
+           {
+             const char *prefix;
+             char *name = 0;
+             struct type *context;
+
+             switch (*++p)
+               {
+               case 'f':
+                 prefix = vptr_name;
+                 break;
+               case 'b':
+                 prefix = vb_name;
+                 break;
+               default:
+                 error ("invalid abbreviation at symtab pos %d.", symnum);
+               }
+             *pp = p + 1;
+             context = read_type (pp);
+             if (type_name_no_tag (context) == 0)
+               {
+                 if (name == 0)
+                   error ("type name unknown at symtab pos %d.", symnum);
+                 /* FIXME-tiemann: when is `name' ever non-0?  */
+                 TYPE_NAME (context) = obsavestring (name, p - name - 1);
+               }
+             list->field.name = obconcat (prefix, type_name_no_tag (context), "");
+             p = ++(*pp);
+             if (p[-1] != ':')
+               error ("invalid abbreviation at symtab pos %d.", symnum);
+             list->field.type = read_type (pp);
+             (*pp)++;                  /* Skip the comma.  */
+             list->field.bitpos = read_number (pp, ';');
+             /* This field is unpacked.  */
+             list->field.bitsize = 0;
+           }
+         /* GNU C++ anonymous type.  */
+         else if (*p == '_')
+           break;
+         else
+           error ("invalid abbreviation at symtab pos %d.", symnum);
+
+         nfields++;
+         continue;
+       }
+
+      while (*p != ':') p++;
+      list->field.name = obsavestring (*pp, p - *pp);
+
+      /* C++: Check to see if we have hit the methods yet.  */
+      if (p[1] == ':')
+       break;
+
+      *pp = p + 1;
+
+      /* This means we have a visibility for a field coming. */
+      if (**pp == '/')
+       {
+         switch (*++*pp)
+           {
+           case '0':
+             list->visibility = 0;     /* private */
+             *pp += 1;
+             break;
+
+           case '1':
+             list->visibility = 1;     /* protected */
+             *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);
+      if (**pp == ':')
+       {
+         /* Static class member.  */
+         list->field.bitpos = (long)-1;
+         p = ++(*pp);
+         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);
+
+      (*pp)++;                 /* Skip the comma.  */
+      list->field.bitpos = read_number (pp, ',');
+      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 (list->field.bitpos == 0
+         && list->field.bitsize == 0)
+       {
+         complain (&dbx_class_complaint, 0);
+         /* Ignore this field.  */
+         list = 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 (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 (builtin_type_int))
+                  )
+              )
+             &&
+             list->field.bitpos % 8 == 0)
+           list->field.bitsize = 0;
+         nfields++;
+       }
+    }
+
+  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.  */
+
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack,
+                                              sizeof (struct field) * nfields);
+
+  TYPE_FIELD_PRIVATE_BITS (type) =
+    (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
+
+  TYPE_FIELD_PROTECTED_BITS (type) =
+    (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
+
+  /* Copy the saved-up fields into the field vector.  */
+
+  for (n = nfields; list; list = list->next)
+    {
+      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);
+    }
+
+  /* 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.
+
+     For the case of overloaded operators, the format is
+     OPERATOR::*.methods, where OPERATOR is the string "operator",
+     `*' holds the place for an operator name (such as `+=')
+     and `.' marks the end of the operator name.  */
+  if (p[1] == ':')
+    {
+      /* Now, read in the methods.  To simplify matters, we
+        "unread" the name that has been read, so that we can
+        start from the top.  */
+
+      /* 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 =
+           (struct next_fnfieldlist *)alloca (sizeof (struct next_fnfieldlist));
+         char *main_fn_name;
+
+         p = *pp;
+
+         /* read in the name.  */
+         while (*p != ':') p++;
+         if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == CPLUS_MARKER)
+           {
+             /* 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 '::'.  */
+             p += 2;
+             while (*p != '.')
+               *o++ = *p++;
+            main_fn_name = savestring (opname, o - opname);
+             /* Skip past '.'  */
+             *pp = p + 1;
+           }
+         else
+           {
+             i = 0;
+             main_fn_name = savestring (*pp, p - *pp);
+             /* Skip past '::'.  */
+             *pp = p + 2;
+           }
+         new_mainlist->fn_fieldlist.name = main_fn_name;
+
+         do
+           {
+             struct next_fnfield *new_sublist =
+               (struct next_fnfield *)alloca (sizeof (struct next_fnfield));
+
+             /* Check for and handle cretinous dbx symbol name continuation!  */
+             if (look_ahead_type == NULL) /* Normal case. */
+               {
+                 if (**pp == '\\') *pp = next_symbol_text ();
+
+                 new_sublist->fn_field.type = read_type (pp);
+                 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.  */
+             new_sublist->fn_field.physname = savestring (*pp, p - *pp);
+             *pp = p + 1;
+             new_sublist->visibility = *(*pp)++ - '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;
+               default:
+                 /* This probably just means we're processing a file compiled
+                    with g++ version 1.  */
+                 complain(&const_vol_complaint, **pp);
+               }
+
+             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);
+                     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;
+                 break;
+               default:
+                 /* **pp == '.'.  */
+                 /* normal member function.  */
+                 new_sublist->fn_field.voffset = 0;
+                 new_sublist->fn_field.fcontext = 0;
+                 break;
+               }
+
+             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 (symbol_obstack,
+                                              sizeof (struct fn_field) * length);
+         TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist) =
+           (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (length));
+         B_CLRALL (TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist), length);
+
+         TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist) =
+           (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (length));
+         B_CLRALL (TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist), length);
+
+         for (i = length; (i--, sublist); sublist = sublist->next)
+           {
+             new_mainlist->fn_fieldlist.fn_fields[i] = sublist->fn_field;
+             if (sublist->visibility == 0)
+               B_SET (new_mainlist->fn_fieldlist.private_fn_field_bits, i);
+             else if (sublist->visibility == 1)
+               B_SET (new_mainlist->fn_fieldlist.protected_fn_field_bits, i);
+           }
+
+         new_mainlist->fn_fieldlist.length = length;
+         new_mainlist->next = mainlist;
+         mainlist = new_mainlist;
+         nfn_fields++;
+         total_length += length;
+       }
+      while (**pp != ';');
+    }
+
+  *pp += 1;
+
+  TYPE_FN_FIELDLISTS (type) =
+    (struct fn_fieldlist *) obstack_alloc (symbol_obstack,
+                                  sizeof (struct fn_fieldlist) * nfn_fields);
+
+  TYPE_NFN_FIELDS (type) = nfn_fields;
+  TYPE_NFN_FIELDS_TOTAL (type) = total_length;
+
+  {
+    int i;
+    for (i = 0; i < TYPE_N_BASECLASSES (type); ++i)
+      TYPE_NFN_FIELDS_TOTAL (type) +=
+       TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, i));
+  }
+
+  for (n = nfn_fields; mainlist; mainlist = mainlist->next)
+    TYPE_FN_FIELDLISTS (type)[--n] = mainlist->fn_fieldlist;
+
+  if (**pp == '~')
+    {
+      *pp += 1;
+
+      if (**pp == '=')
+       {
+         TYPE_FLAGS (type)
+           |= TYPE_FLAG_HAS_CONSTRUCTOR | TYPE_FLAG_HAS_DESTRUCTOR;
+         *pp += 1;
+       }
+      else if (**pp == '+')
+       {
+         TYPE_FLAGS (type) |= TYPE_FLAG_HAS_CONSTRUCTOR;
+         *pp += 1;
+       }
+      else if (**pp == '-')
+       {
+         TYPE_FLAGS (type) |= TYPE_FLAG_HAS_DESTRUCTOR;
+         *pp += 1;
+       }
+
+      /* Read either a '%' or the final ';'.  */
+      if (*(*pp)++ == '%')
+       {
+         /* Now we must record the virtual function table pointer's
+            field information.  */
+
+         struct type *t;
+         int i;
+
+         t = read_type (pp);
+         p = (*pp)++;
+         while (*p != '\0' && *p != ';')
+           p++;
+         if (*p == '\0')
+           /* Premature end of symbol.  */
+           return error_type (pp);
+         
+         TYPE_VPTR_BASETYPE (type) = t;
+         if (type == t)
+           {
+             if (TYPE_FIELD_NAME (t, TYPE_N_BASECLASSES (t)) == 0)
+               {
+                 /* FIXME-tiemann: what's this?  */
+#if 0
+                 TYPE_VPTR_FIELDNO (type) = i = TYPE_N_BASECLASSES (t);
+#else
+                 error_type (pp);
+#endif
+               }
+             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);
+           }
+         else
+           TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t);
+         *pp = p + 1;
+       }
+    }
+
+  return type;
+}
+
+/* Read a definition of an array type,
+   and create and return a suitable type object.
+   Also creates a range type which represents the bounds of that
+   array.  */
+struct type *
+read_array_type (pp, type)
+     register char **pp;
+     register struct type *type;
+{
+  struct type *index_type, *element_type, *range_type;
+  int lower, upper;
+  int adjustable = 0;
+
+  /* Format of an array type:
+     "ar<index type>;lower;upper;<array_contents_type>".  Put code in
+     to handle this.
+
+     Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+     for these, produce a type like float[][].  */
+
+  index_type = read_type (pp);
+  if (**pp != ';')
+    /* Improper format of array type decl.  */
+    return error_type (pp);
+  ++*pp;
+
+  if (!(**pp >= '0' && **pp <= '9'))
+    {
+      *pp += 1;
+      adjustable = 1;
+    }
+  lower = read_number (pp, ';');
+
+  if (!(**pp >= '0' && **pp <= '9'))
+    {
+      *pp += 1;
+      adjustable = 1;
+    }
+  upper = read_number (pp, ';');
+  
+  element_type = read_type (pp);
+
+  if (adjustable)
+    {
+      lower = 0;
+      upper = -1;
+    }
+
+  {
+    /* Create range type.  */
+    range_type = (struct type *) obstack_alloc (symbol_obstack,
+                                               sizeof (struct type));
+    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 (symbol_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 (symbol_obstack,
+                                   sizeof (struct field));
+  TYPE_FIELD_TYPE (type, 0) = range_type;
+
+  return type;
+}
+
+
+/* Read a definition of an enumeration type,
+   and create and return a suitable type object.
+   Also defines the symbols that represent the values of the type.  */
+
+struct type *
+read_enum_type (pp, type)
+     register char **pp;
+     register struct type *type;
+{
+  register char *p;
+  char *name;
+  register long n;
+  register struct symbol *sym;
+  int nsyms = 0;
+  struct pending **symlist;
+  struct pending *osyms, *syms;
+  int o_nsyms;
+
+  if (within_function)
+    symlist = &local_symbols;
+  else
+    symlist = &file_symbols;
+  osyms = *symlist;
+  o_nsyms = osyms ? osyms->nsyms : 0;
+
+  /* Read the value-names and their values.
+     The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+     A semicolon or comman 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 ();
+
+      p = *pp;
+      while (*p != ':') p++;
+      name = obsavestring (*pp, p - *pp);
+      *pp = p + 1;
+      n = read_number (pp, ',');
+
+      sym = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+      bzero (sym, sizeof (struct symbol));
+      SYMBOL_NAME (sym) = name;
+      SYMBOL_CLASS (sym) = LOC_CONST;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      SYMBOL_VALUE (sym) = n;
+      add_symbol_to_list (sym, symlist);
+      nsyms++;
+    }
+
+  if (**pp == ';')
+    (*pp)++;                   /* Skip the semicolon.  */
+
+  /* Now fill in the fields of the type-structure.  */
+
+  TYPE_LENGTH (type) = sizeof (int);
+  TYPE_CODE (type) = TYPE_CODE_ENUM;
+  TYPE_NFIELDS (type) = nsyms;
+  TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack, 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
+     to cause them to be defined.  osyms contains the old value
+     of that symlist; everything up to there was defined by us.  */
+  /* Note that we preserve the order of the enum constants, so
+     that in something like "enum {FOO, LAST_THING=FOO}" we print
+     FOO, not LAST_THING.  */
+
+  for (syms = *symlist, n = 0; syms; syms = syms->next)
+    {
+      int j = 0;
+      if (syms == osyms)
+       j = o_nsyms;
+      for (; j < syms->nsyms; j++,n++)
+       {
+         struct symbol *xsym = syms->symbol[j];
+         SYMBOL_TYPE (xsym) = type;
+         TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym);
+         TYPE_FIELD_VALUE (type, n) = 0;
+         TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+         TYPE_FIELD_BITSIZE (type, n) = 0;
+       }
+      if (syms == osyms)
+       break;
+    }
+
+#if 0
+  /* 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"))))
+     TYPE_CODE(type) = TYPE_CODE_BOOL;
+#endif
+
+  return type;
+}
+
+/* Read a number from the string pointed to by *PP.
+   The value of *PP is advanced over the number.
+   If END is nonzero, the character that ends the
+   number must match END, or an error happens;
+   and that character is skipped if it does match.
+   If END is zero, *PP is left pointing to that character.
+
+   If the number fits in a long, set *VALUE and set *BITS to 0.
+   If not, set *BITS to be the number of bits in the number.
+
+   If encounter garbage, set *BITS to -1.  */
+
+void
+read_huge_number (pp, end, valu, bits)
+     char **pp;
+     int end;
+     long *valu;
+     int *bits;
+{
+  char *p = *pp;
+  int sign = 1;
+  long n = 0;
+  int radix = 10;
+  char overflow = 0;
+  int nbits = 0;
+  int c;
+  long upper_limit;
+  
+  if (*p == '-')
+    {
+      sign = -1;
+      p++;
+    }
+
+  /* Leading zero means octal.  GCC uses this to output values larger
+     than an int (because that would be hard in decimal).  */
+  if (*p == '0')
+    {
+      radix = 8;
+      p++;
+    }
+
+  upper_limit = LONG_MAX / radix;
+  while ((c = *p++) >= '0' && c <= ('0' + radix))
+    {
+      if (n <= upper_limit)
+       {
+         n *= radix;
+         n += c - '0';         /* FIXME this overflows anyway */
+       }
+      else
+       overflow = 1;
+      
+      /* This depends on large values being output in octal, which is
+        what GCC does. */
+      if (radix == 8)
+       {
+         if (nbits == 0)
+           {
+             if (c == '0')
+               /* Ignore leading zeroes.  */
+               ;
+             else if (c == '1')
+               nbits = 1;
+             else if (c == '2' || c == '3')
+               nbits = 2;
+             else
+               nbits = 3;
+           }
+         else
+           nbits += 3;
+       }
+    }
+  if (end)
+    {
+      if (c && c != end)
+       {
+         if (bits != NULL)
+           *bits = -1;
+         return;
+       }
+    }
+  else
+    --p;
+
+  *pp = p;
+  if (overflow)
+    {
+      if (nbits == 0)
+       {
+         /* Large decimal constants are an error (because it is hard to
+            count how many bits are in them).  */
+         if (bits != NULL)
+           *bits = -1;
+         return;
+       }
+      
+      /* -0x7f is the same as 0x80.  So deal with it by adding one to
+        the number of bits.  */
+      if (sign == -1)
+       ++nbits;
+      if (bits)
+       *bits = nbits;
+    }
+  else
+    {
+      if (valu)
+       *valu = n * sign;
+      if (bits)
+       *bits = 0;
+    }
+}
+
+#define        MAX_OF_C_TYPE(t)        ((1 << (sizeof (t)*8 - 1)) - 1)
+#define        MIN_OF_C_TYPE(t)        (-(1 << (sizeof (t)*8 - 1)))
+
+struct type *
+read_range_type (pp, typenums)
+     char **pp;
+     int typenums[2];
+{
+  int rangenums[2];
+  long n2, n3;
+  int n2bits, n3bits;
+  int self_subrange;
+  struct type *result_type;
+
+  /* First comes a type we are a subrange of.
+     In C it is usually 0, 1 or the type being defined.  */
+  read_type_number (pp, rangenums);
+  self_subrange = (rangenums[0] == typenums[0] &&
+                  rangenums[1] == typenums[1]);
+
+  /* A semicolon should now follow; skip it.  */
+  if (**pp == ';')
+    (*pp)++;
+
+  /* The remaining two operands are usually lower and upper bounds
+     of the range.  But in some special cases they mean something else.  */
+  read_huge_number (pp, ';', &n2, &n2bits);
+  read_huge_number (pp, ';', &n3, &n3bits);
+
+  if (n2bits == -1 || n3bits == -1)
+    return error_type (pp);
+  
+  /* If limits are huge, must be large integral type.  */
+  if (n2bits != 0 || n3bits != 0)
+    {
+      char got_signed = 0;
+      char got_unsigned = 0;
+      /* Number of bits in the type.  */
+      int nbits;
+
+      /* Range from 0 to <large number> is an unsigned large integral type.  */
+      if ((n2bits == 0 && n2 == 0) && n3bits != 0)
+       {
+         got_unsigned = 1;
+         nbits = n3bits;
+       }
+      /* Range from <large number> to <large number>-1 is a large signed
+        integral type.  */
+      else if (n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1)
+       {
+         got_signed = 1;
+         nbits = n2bits;
+       }
+
+      /* Check for "long long".  */
+      if (got_signed && nbits == TARGET_LONG_LONG_BIT)
+       return builtin_type_long_long;
+      if (got_unsigned && nbits == TARGET_LONG_LONG_BIT)
+       return builtin_type_unsigned_long_long;
+
+      if (got_signed || got_unsigned)
+       {
+         result_type = (struct type *) obstack_alloc (symbol_obstack,
+                                                      sizeof (struct type));
+         bzero (result_type, sizeof (struct type));
+         TYPE_LENGTH (result_type) = nbits / TARGET_CHAR_BIT;
+         TYPE_MAIN_VARIANT (result_type) = result_type;
+         TYPE_CODE (result_type) = TYPE_CODE_INT;
+         if (got_unsigned)
+           TYPE_FLAGS (result_type) |= TYPE_FLAG_UNSIGNED;
+         return result_type;
+       }
+      else
+       return error_type (pp);
+    }
+
+  /* A type defined as a subrange of itself, with bounds both 0, is void.  */
+  if (self_subrange && n2 == 0 && n3 == 0)
+    return builtin_type_void;
+
+  /* If n3 is zero and n2 is not, we want a floating type,
+     and n2 is the width in bytes.
+
+     Fortran programs appear to use this for complex types also,
+     and they give no way to distinguish between double and single-complex!
+     We don't have complex types, so we would lose on all fortran files!
+     So return type `double' for all of those.  It won't work right
+     for the complex values, but at least it makes the file loadable.  */
+
+  if (n3 == 0 && n2 > 0)
+    {
+      if (n2 == sizeof (float))
+       return builtin_type_float;
+      return builtin_type_double;
+    }
+
+  /* If the upper bound is -1, it must really be an unsigned int.  */
+
+  else if (n2 == 0 && n3 == -1)
+    {
+      if (sizeof (int) == sizeof (long))
+       return builtin_type_unsigned_int;
+      else
+       return builtin_type_unsigned_long;
+    }
+
+  /* Special case: char is defined (Who knows why) as a subrange of
+     itself with range 0-127.  */
+  else if (self_subrange && n2 == 0 && n3 == 127)
+    return builtin_type_char;
+
+  /* Assumptions made here: Subrange of self is equivalent to subrange
+     of int.  */
+  else if (n2 == 0
+          && (self_subrange ||
+              *dbx_lookup_type (rangenums) == builtin_type_int))
+    {
+      /* an unsigned type */
+#ifdef LONG_LONG
+      if (n3 == - sizeof (long long))
+       return builtin_type_unsigned_long_long;
+#endif
+      if (n3 == (unsigned int)~0L)
+       return builtin_type_unsigned_int;
+      if (n3 == (unsigned long)~0L)
+       return builtin_type_unsigned_long;
+      if (n3 == (unsigned short)~0L)
+       return builtin_type_unsigned_short;
+      if (n3 == (unsigned char)~0L)
+       return builtin_type_unsigned_char;
+    }
+#ifdef LONG_LONG
+  else if (n3 == 0 && n2 == -sizeof (long long))
+    return builtin_type_long_long;
+#endif  
+  else if (n2 == -n3 -1)
+    {
+      /* a signed type */
+      if (n3 == (1 << (8 * sizeof (int) - 1)) - 1)
+       return builtin_type_int;
+      if (n3 == (1 << (8 * sizeof (long) - 1)) - 1)
+        return builtin_type_long;
+      if (n3 == (1 << (8 * sizeof (short) - 1)) - 1)
+       return builtin_type_short;
+      if (n3 == (1 << (8 * sizeof (char) - 1)) - 1)
+       return builtin_type_char;
+    }
+
+  /* We have a real range type on our hands.  Allocate space and
+     return a real pointer.  */
+
+  /* At this point I don't have the faintest idea how to deal with
+     a self_subrange type; I'm going to assume that this is used
+     as an idiom, and that all of them are special cases.  So . . .  */
+  if (self_subrange)
+    return error_type (pp);
+
+  result_type = (struct type *) obstack_alloc (symbol_obstack,
+                                              sizeof (struct type));
+  bzero (result_type, sizeof (struct type));
+
+  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, rangenums[1]);
+    TYPE_TARGET_TYPE (result_type) = builtin_type_int;
+  }
+
+  TYPE_NFIELDS (result_type) = 2;
+  TYPE_FIELDS (result_type) =
+     (struct field *) obstack_alloc (symbol_obstack,
+                                    2 * sizeof (struct field));
+  bzero (TYPE_FIELDS (result_type), 2 * sizeof (struct field));
+  TYPE_FIELD_BITPOS (result_type, 0) = n2;
+  TYPE_FIELD_BITPOS (result_type, 1) = n3;
+
+#if 0
+/* Note that TYPE_LENGTH (result_type) is just overridden a few
+   statements down.  What do we really need here?  */
+  /* We have to figure out how many bytes it takes to hold this
+     range type.  I'm going to assume that anything that is pushing
+     the bounds of a long was taken care of above.  */
+  if (n2 >= MIN_OF_C_TYPE(char) && n3 <= MAX_OF_C_TYPE(char))
+    TYPE_LENGTH (result_type) = 1;
+  else if (n2 >= MIN_OF_C_TYPE(short) && n3 <= MAX_OF_C_TYPE(short))
+    TYPE_LENGTH (result_type) = sizeof (short);
+  else if (n2 >= MIN_OF_C_TYPE(int) && n3 <= MAX_OF_C_TYPE(int))
+    TYPE_LENGTH (result_type) = sizeof (int);
+  else if (n2 >= MIN_OF_C_TYPE(long) && n3 <= MAX_OF_C_TYPE(long))
+    TYPE_LENGTH (result_type) = sizeof (long);
+  else
+    /* Ranged type doesn't fit within known sizes.  */
+    /* FIXME -- use "long long" here.  */
+    return error_type (pp);
+#endif
+
+  TYPE_LENGTH (result_type) = TYPE_LENGTH (TYPE_TARGET_TYPE (result_type));
+
+  return result_type;
+}
+
+/* Read a number from the string pointed to by *PP.
+   The value of *PP is advanced over the number.
+   If END is nonzero, the character that ends the
+   number must match END, or an error happens;
+   and that character is skipped if it does match.
+   If END is zero, *PP is left pointing to that character.  */
+
+long
+read_number (pp, end)
+     char **pp;
+     int end;
+{
+  register char *p = *pp;
+  register long n = 0;
+  register int c;
+  int sign = 1;
+
+  /* Handle an optional leading minus sign.  */
+
+  if (*p == '-')
+    {
+      sign = -1;
+      p++;
+    }
+
+  /* Read the digits, as far as they go.  */
+
+  while ((c = *p++) >= '0' && c <= '9')
+    {
+      n *= 10;
+      n += c - '0';
+    }
+  if (end)
+    {
+      if (c && c != end)
+       error ("Invalid symbol data: invalid character \\%03o at symbol pos %d.", c, symnum);
+    }
+  else
+    --p;
+
+  *pp = p;
+  return n * sign;
+}
+
+/* Read in an argument list.  This is a list of types, separated by commas
+   and terminated with END.  Return the list of types read in, or (struct type
+   **)-1 if there is an error.  */
+struct type **
+read_args (pp, end)
+     char **pp;
+     int end;
+{
+  struct type *types[1024], **rval; /* allow for fns of 1023 parameters */
+  int n = 0;
+
+  while (**pp != end)
+    {
+      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 ();
+
+      types[n++] = read_type (pp);
+    }
+  *pp += 1;                    /* get past `end' (the ':' character) */
+
+  if (n == 1)
+    {
+      rval = (struct type **) xmalloc (2 * sizeof (struct type *));
+    }
+  else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID)
+    {
+      rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *));
+      bzero (rval + n, sizeof (struct type *));
+    }
+  else
+    {
+      rval = (struct type **) xmalloc (n * sizeof (struct type *));
+    }
+  bcopy (types, rval, n * sizeof (struct type *));
+  return rval;
+}
+
+/* Add a common block's start address to the offset of each symbol
+   declared to be in it (by being between a BCOMM/ECOMM pair that uses
+   the common block name).  */
+
+static void
+fix_common_block (sym, valu)
+    struct symbol *sym;
+    int valu;
+{
+  struct pending *next = (struct pending *) SYMBOL_NAMESPACE (sym);
+  for ( ; next; next = next->next)
+    {
+      register int j;
+      for (j = next->nsyms - 1; j >= 0; j--)
+       SYMBOL_VALUE_ADDRESS (next->symbol[j]) += valu;
+    }
+}
+
+/* Initializer for this module */
+void
+_initialize_buildsym ()
+{
+  undef_types_allocated = 20;
+  undef_types_length = 0;
+  undef_types = (struct type **) xmalloc (undef_types_allocated *
+                                         sizeof (struct type *));
+}
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
new file mode 100644 (file)
index 0000000..7cef879
--- /dev/null
@@ -0,0 +1,274 @@
+/* Build symbol tables in GDB's internal format.
+   Copyright (C) 1986-1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* This module provides definitions used for creating and adding to
+   the symbol table.  These routines are called from various symbol-
+   file-reading routines.  
+
+   They originated in dbxread.c of gdb-4.2, and were split out to
+   make xcoffread.c more maintainable by sharing code.
+
+   Variables declared in this file can be defined by #define-ing
+   the name EXTERN to null.  It is used to declare variables that
+   are normally extern, but which get defined in a single module
+   using this technique.  */
+
+#ifndef EXTERN
+#define        EXTERN  extern
+#endif
+
+extern void add_symbol_to_list ();
+extern void process_one_symbol ();
+extern struct type *read_type ();
+extern struct type *read_range_type ();
+extern struct type *read_enum_type ();
+extern struct type *read_struct_type ();
+extern struct type *read_array_type ();
+extern struct type **read_args ();
+extern struct type **dbx_lookup_type ();
+extern long read_number ();
+extern void finish_block ();
+extern struct blockvector *make_blockvector ();
+extern void add_undefined_type ();
+extern void really_free_pendings ();
+extern struct symtab *end_symtab ();
+extern void scan_file_globals ();
+extern void buildsym_new_init ();
+extern void buildsym_init ();
+
+/* Convert stab register number (from `r' declaration) to a gdb REGNUM.  */
+
+#ifndef STAB_REG_TO_REGNUM
+#define STAB_REG_TO_REGNUM(VALUE) (VALUE)
+#endif
+\f
+/* Name of source file whose symbol data we are now processing.
+   This comes from a symbol of type N_SO.  */
+
+EXTERN char *last_source_file;
+
+/* Core address of start of text of current source file.
+   This too comes from the N_SO symbol.  */
+
+EXTERN CORE_ADDR last_source_start_addr;
+
+/* The list of sub-source-files within the current individual compilation.
+   Each file gets its own symtab with its own linetable and associated info,
+   but they all share one blockvector.  */
+
+struct subfile
+{
+  struct subfile *next;
+  char *name;
+  char *dirname;
+  struct linetable *line_vector;
+  int line_vector_length;
+  int line_vector_index;
+  int prev_line_number;
+};
+
+EXTERN struct subfile *subfiles;
+
+EXTERN struct subfile *current_subfile;
+
+/* Global variable which, when set, indicates that we are processing a
+   .o file compiled with gcc */
+
+EXTERN unsigned char processing_gcc_compilation;
+
+/* Count symbols as they are processed, for error messages.  */
+
+EXTERN unsigned int symnum;
+
+/* Vector of types defined so far, indexed by their dbx type numbers.
+   (In newer sun systems, dbx uses a pair of numbers in parens,
+    as in "(SUBFILENUM,NUMWITHINSUBFILE)".  Then these numbers must be
+    translated through the type_translations hash table to get
+    the index into the type vector.)  */
+
+EXTERN struct type **type_vector;
+
+/* Number of elements allocated for type_vector currently.  */
+
+EXTERN int type_vector_length;
+
+/* Vector of line number information.  */
+
+EXTERN struct linetable *line_vector;
+
+/* Index of next entry to go in line_vector_index.  */
+
+EXTERN int line_vector_index;
+
+/* Last line number recorded in the line vector.  */
+
+EXTERN int prev_line_number;
+
+/* Number of elements allocated for line_vector currently.  */
+
+EXTERN int line_vector_length;
+
+/* Hash table of global symbols whose values are not known yet.
+   They are chained thru the SYMBOL_VALUE_CHAIN, since we don't
+   have the correct data for that slot yet.  */
+/* The use of the LOC_BLOCK code in this chain is nonstandard--
+   it refers to a FORTRAN common block rather than the usual meaning.  */
+
+#define HASHSIZE 127
+EXTERN struct symbol *global_sym_chain[HASHSIZE];
+
+/* Record the symbols defined for each context in a list.
+   We don't create a struct block for the context until we
+   know how long to make it.  */
+
+#define PENDINGSIZE 100
+
+struct pending
+{
+  struct pending *next;
+  int nsyms;
+  struct symbol *symbol[PENDINGSIZE];
+};
+
+/* List of free `struct pending' structures for reuse.  */
+EXTERN struct pending *free_pendings;
+
+/* Here are the three lists that symbols are put on.  */
+
+EXTERN struct pending *file_symbols;   /* static at top level, and types */
+
+EXTERN struct pending *global_symbols; /* global functions and variables */
+
+EXTERN struct pending *local_symbols;  /* everything local to lexical context */
+
+/* List of symbols declared since the last BCOMM.  This list is a tail
+   of local_symbols.  When ECOMM is seen, the symbols on the list
+   are noted so their proper addresses can be filled in later,
+   using the common block base address gotten from the assembler
+   stabs.  */
+
+EXTERN struct pending *common_block;
+EXTERN int common_block_i;
+
+/* Stack representing unclosed lexical contexts
+   (that will become blocks, eventually).  */
+
+struct context_stack
+{
+  struct pending *locals;
+  struct pending_block *old_blocks;
+  struct symbol *name;
+  CORE_ADDR start_addr;
+  CORE_ADDR end_addr;          /* Temp slot for exception handling. */
+  int depth;
+};
+
+EXTERN struct context_stack *context_stack;
+
+/* Index of first unused entry in context stack.  */
+EXTERN int context_stack_depth;
+
+/* Currently allocated size of context stack.  */
+
+EXTERN int context_stack_size;
+
+/* Nonzero if within a function (so symbols should be local,
+   if nothing says specifically).  */
+
+EXTERN int within_function;
+
+/* List of blocks already made (lexical contexts already closed).
+   This is used at the end to make the blockvector.  */
+
+struct pending_block
+{
+  struct pending_block *next;
+  struct block *block;
+};
+
+EXTERN struct pending_block *pending_blocks;
+
+extern CORE_ADDR startup_file_start;   /* From blockframe.c */
+extern CORE_ADDR startup_file_end;     /* From blockframe.c */
+
+/* Global variable which, when set, indicates that we are processing a
+   .o file compiled with gcc */
+
+EXTERN unsigned char processing_gcc_compilation;
+
+/* Setup a define to deal cleanly with the underscore problem */
+
+#ifdef NAMES_HAVE_UNDERSCORE
+#define HASH_OFFSET 1
+#else
+#define HASH_OFFSET 0
+#endif
+\f
+/* Support for Sun changes to dbx symbol format */
+
+/* For each identified header file, we have a table of types defined
+   in that header file.
+
+   header_files maps header file names to their type tables.
+   It is a vector of n_header_files elements.
+   Each element describes one header file.
+   It contains a vector of types.
+
+   Sometimes it can happen that the same header file produces
+   different results when included in different places.
+   This can result from conditionals or from different
+   things done before including the file.
+   When this happens, there are multiple entries for the file in this table,
+   one entry for each distinct set of results.
+   The entries are distinguished by the INSTANCE field.
+   The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is
+   used to match header-file references to their corresponding data.  */
+
+struct header_file
+{
+  char *name;                  /* Name of header file */
+  int instance;                        /* Numeric code distinguishing instances
+                                  of one header file that produced
+                                  different results when included.
+                                  It comes from the N_BINCL or N_EXCL.  */
+  struct type **vector;                /* Pointer to vector of types */
+  int length;                  /* Allocated length (# elts) of that vector */
+};
+
+EXTERN struct header_file *header_files;
+
+EXTERN int n_header_files;
+
+EXTERN int n_allocated_header_files;
+
+/* Within each object file, various header files are assigned numbers.
+   A type is defined or referred to with a pair of numbers
+   (FILENUM,TYPENUM) where FILENUM is the number of the header file
+   and TYPENUM is the number within that header file.
+   TYPENUM is the index within the vector of types for that header file.
+
+   FILENUM == 1 is special; it refers to the main source of the object file,
+   and not to any header file.  FILENUM != 1 is interpreted by looking it up
+   in the following table, which contains indices in header_files.  */
+
+EXTERN int *this_object_header_files;
+
+EXTERN int n_this_object_header_files;
+
+EXTERN int n_allocated_this_object_header_files;
index 7fb59c7f0c1ff6620374e13bd933561e4edd3d15..822a2f47aaf445397cc829ac97f6b1e69735e577 100644 (file)
@@ -55,68 +55,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "gdbcore.h"           /* for bfd stuff */
 #include "libaout.h"           /* FIXME Secret internal BFD stuff for a.out */
 #include "symfile.h"
+#include "buildsym.h"
 
 #include "aout64.h"
 #include "stab.gnu.h"          /* We always use GNU stabs, not native, now */
 
-#ifndef NO_GNU_STABS
-/*
- * Define specifically gnu symbols here.
- */
-
-/* The following type indicates the definition of a symbol as being
-   an indirect reference to another symbol.  The other symbol
-   appears as an undefined reference, immediately following this symbol.
-
-   Indirection is asymmetrical.  The other symbol's value will be used
-   to satisfy requests for the indirect symbol, but not vice versa.
-   If the other symbol does not have a definition, libraries will
-   be searched to find a definition.  */
-#ifndef N_INDR
-#define N_INDR 0xa
-#endif
-
-/* The following symbols refer to set elements.
-   All the N_SET[ATDB] symbols with the same name form one set.
-   Space is allocated for the set in the text section, and each set
-   element's value is stored into one word of the space.
-   The first word of the space is the length of the set (number of elements).
-
-   The address of the set is made into an N_SETV symbol
-   whose name is the same as the name of the set.
-   This symbol acts like a N_DATA global symbol
-   in that it can satisfy undefined external references.  */
-
-#ifndef N_SETA
-#define        N_SETA  0x14            /* Absolute set element symbol */
-#endif                         /* This is input to LD, in a .o file.  */
-
-#ifndef N_SETT
-#define        N_SETT  0x16            /* Text set element symbol */
-#endif                         /* This is input to LD, in a .o file.  */
-
-#ifndef N_SETD
-#define        N_SETD  0x18            /* Data set element symbol */
-#endif                         /* This is input to LD, in a .o file.  */
-
-#ifndef N_SETB
-#define        N_SETB  0x1A            /* Bss set element symbol */
-#endif                         /* This is input to LD, in a .o file.  */
-
-/* Macros dealing with the set element symbols defined in a.out.h */
-#define        SET_ELEMENT_P(x)        ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT))
-#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS)
-
-#ifndef N_SETV
-#define N_SETV 0x1C            /* Pointer to set vector in data area.  */
-#endif                         /* This is output from LD.  */
-
-#ifndef N_WARNING
-#define N_WARNING 0x1E         /* Warning message to print if file included */
-#endif                         /* This is input to ld */
-
-#endif /* NO_GNU_STABS */
-
+/* Information is passed among various dbxread routines for accessing
+   symbol files.  A pointer to this structure is kept in the sym_private
+   field of the struct sym_fns passed in by symfile.h.  */
 struct dbx_symfile_info {
   asection *text_sect;         /* Text section accessor */
   int symcount;                        /* How many symbols are there in the file */
@@ -126,6 +73,7 @@ struct dbx_symfile_info {
   int desc;                    /* File descriptor of symbol file */
 };
 
+
 /* Each partial symbol table entry contains a pointer to private data for the
    read_symtab() function to use when expanding a partial symbol table entry
    to a full symbol table entry.
@@ -147,38 +95,19 @@ struct symloc {
 
 extern void qsort ();
 extern double atof ();
-extern struct cmd_list_element *cmdlist;
-
-extern void symbol_file_command ();
 
 /* Forward declarations */
 
-static void add_symbol_to_list ();
 static void read_dbx_symtab ();
 static void init_psymbol_list ();
 static void process_one_symbol ();
-static struct type *read_type ();
-static struct type *read_range_type ();
-static struct type *read_enum_type ();
-static struct type *read_struct_type ();
-static struct type *read_array_type ();
-static long read_number ();
-static void finish_block ();
-static struct blockvector *make_blockvector ();
 static struct symbol *define_symbol ();
-static void start_subfile ();
-static int hashname ();
+void start_subfile ();
+int hashname ();
 static struct pending *copy_pending ();
-static void fix_common_block ();
-static void add_undefined_type ();
-static void cleanup_undefined_types ();
-static void scan_file_globals ();
 static struct symtab *read_ofile_symtab ();
 static void dbx_psymtab_to_symtab ();
 
-/* C++ */
-static struct type **read_args ();
-
 static const char vptr_name[] = { '_','v','p','t','r',CPLUS_MARKER,'\0' };
 static const char vb_name[] =   { '_','v','b',CPLUS_MARKER,'\0' };
 
@@ -194,12 +123,6 @@ static const char vb_name[] =   { '_','v','b',CPLUS_MARKER,'\0' };
 #define GCC_COMPILED_FLAG_SYMBOL "gcc_compiled."
 #endif
 
-/* Convert stab register number (from `r' declaration) to a gdb REGNUM.  */
-
-#ifndef STAB_REG_TO_REGNUM
-#define STAB_REG_TO_REGNUM(VALUE) (VALUE)
-#endif
-
 /* Define this as 1 if a pcc declaration of a char or short argument
    gives the correct address.  Otherwise assume pcc gives the
    address of the corresponding int, which is not the same on a
@@ -208,172 +131,14 @@ static const char vb_name[] =   { '_','v','b',CPLUS_MARKER,'\0' };
 #ifndef BELIEVE_PCC_PROMOTION
 #define BELIEVE_PCC_PROMOTION 0
 #endif
-\f
+
 /* Nonzero means give verbose info on gdb action.  From main.c.  */
 extern int info_verbose;
 
-/* Name of source file whose symbol data we are now processing.
-   This comes from a symbol of type N_SO.  */
-
-static char *last_source_file;
-
-/* Core address of start of text of current source file.
-   This too comes from the N_SO symbol.  */
-
-static CORE_ADDR last_source_start_addr;
-
-/* The entry point of a file we are reading.  */
-CORE_ADDR entry_point;
-
-/* The list of sub-source-files within the current individual compilation.
-   Each file gets its own symtab with its own linetable and associated info,
-   but they all share one blockvector.  */
-
-struct subfile
-{
-  struct subfile *next;
-  char *name;
-  char *dirname;
-  struct linetable *line_vector;
-  int line_vector_length;
-  int line_vector_index;
-  int prev_line_number;
-};
-
-static struct subfile *subfiles;
-
-static struct subfile *current_subfile;
-
-/* Count symbols as they are processed, for error messages.  */
-
-static unsigned int symnum;
-
-/* Vector of types defined so far, indexed by their dbx type numbers.
-   (In newer sun systems, dbx uses a pair of numbers in parens,
-    as in "(SUBFILENUM,NUMWITHINSUBFILE)".  Then these numbers must be
-    translated through the type_translations hash table to get
-    the index into the type vector.)  */
-
-static struct type **type_vector;
-
-/* Number of elements allocated for type_vector currently.  */
-
-static int type_vector_length;
-
-/* Vector of line number information.  */
-
-static struct linetable *line_vector;
-
-/* Index of next entry to go in line_vector_index.  */
-
-static int line_vector_index;
-
-/* Last line number recorded in the line vector.  */
-
-static int prev_line_number;
-
-/* Number of elements allocated for line_vector currently.  */
-
-static int line_vector_length;
-
-/* Hash table of global symbols whose values are not known yet.
-   They are chained thru the SYMBOL_VALUE_CHAIN, since we don't
-   have the correct data for that slot yet.  */
-/* The use of the LOC_BLOCK code in this chain is nonstandard--
-   it refers to a FORTRAN common block rather than the usual meaning.  */
-
-#define HASHSIZE 127
-static struct symbol *global_sym_chain[HASHSIZE];
-
-/* Record the symbols defined for each context in a list.
-   We don't create a struct block for the context until we
-   know how long to make it.  */
-
-#define PENDINGSIZE 100
-
-struct pending
-{
-  struct pending *next;
-  int nsyms;
-  struct symbol *symbol[PENDINGSIZE];
-};
-
-/* List of free `struct pending' structures for reuse.  */
-struct pending *free_pendings;
-
-/* Here are the three lists that symbols are put on.  */
-
-struct pending *file_symbols;  /* static at top level, and types */
-
-struct pending *global_symbols;        /* global functions and variables */
-
-struct pending *local_symbols; /* everything local to lexical context */
-
-/* List of symbols declared since the last BCOMM.  This list is a tail
-   of local_symbols.  When ECOMM is seen, the symbols on the list
-   are noted so their proper addresses can be filled in later,
-   using the common block base address gotten from the assembler
-   stabs.  */
-
-struct pending *common_block;
-int common_block_i;
-
-/* Stack representing unclosed lexical contexts
-   (that will become blocks, eventually).  */
-
-struct context_stack
-{
-  struct pending *locals;
-  struct pending_block *old_blocks;
-  struct symbol *name;
-  CORE_ADDR start_addr;
-  CORE_ADDR end_addr;          /* Temp slot for exception handling. */
-  int depth;
-};
-
-struct context_stack *context_stack;
-
-/* Index of first unused entry in context stack.  */
-int context_stack_depth;
-
-/* Currently allocated size of context stack.  */
-
-int context_stack_size;
-
-/* Nonzero if within a function (so symbols should be local,
-   if nothing says specifically).  */
-
-int within_function;
-
-#if 0
-/* The type of the function we are currently reading in.  This is
-   used by define_symbol to record the type of arguments to a function. */
-
-static struct type *in_function_type;
-#endif
-
-/* List of blocks already made (lexical contexts already closed).
-   This is used at the end to make the blockvector.  */
-
-struct pending_block
-{
-  struct pending_block *next;
-  struct block *block;
-};
-
-struct pending_block *pending_blocks;
-
-extern CORE_ADDR startup_file_start;   /* From blockframe.c */
-extern CORE_ADDR startup_file_end;     /* From blockframe.c */
-
-/* Global variable which, when set, indicates that we are processing a
-   .o file compiled with gcc */
-
-static unsigned char processing_gcc_compilation;
+/* The BFD for this file -- only good while we're actively reading
+   symbols into a psymtab or a symtab.  */
 
-/* Make a list of forward references which haven't been defined.  */
-static struct type **undef_types;
-static int undef_types_allocated, undef_types_length;
+static bfd *symfile_bfd;
 
 /* String table for the main symbol file.  It is kept in memory
    permanently, to speed up symbol reading.  Other files' symbol tables
@@ -388,33 +153,11 @@ static int symfile_string_table_size;
 
 static unsigned symbol_size;
 
-/* Setup a define to deal cleanly with the underscore problem */
-
-#ifdef NAMES_HAVE_UNDERSCORE
-#define HASH_OFFSET 1
-#else
-#define HASH_OFFSET 0
-#endif
-
 /* Complaints about the symbols we have encountered.  */
 
-struct complaint innerblock_complaint =
-  {"inner block not inside outer block in %s", 0, 0};
-
-struct complaint blockvector_complaint = 
-  {"block at %x out of order", 0, 0};
-
 struct complaint lbrac_complaint = 
   {"bad block start address patched", 0, 0};
 
-#if 0
-struct complaint dbx_class_complaint =
-  {"encountered DBX-style class variable debugging information.\n\
-You seem to have compiled your program with \
-\"g++ -g0\" instead of \"g++ -g\".\n\
-Therefore GDB will not know about your class variables", 0, 0};
-#endif
-
 struct complaint string_table_offset_complaint =
   {"bad string table offset in symbol %d", 0, 0};
 
@@ -423,56 +166,7 @@ struct complaint unknown_symtype_complaint =
 
 struct complaint lbrac_rbrac_complaint =
   {"block start larger than block end", 0, 0};
-
-struct complaint const_vol_complaint =
-  {"const/volatile indicator missing (ok if using g++ v1.x), got '%c'", 0, 0};
-
-struct complaint error_type_complaint =
-  {"debug info mismatch between compiler and debugger", 0, 0};
-
-struct complaint invalid_member_complaint =
-  {"invalid (minimal) member type data format at symtab pos %d.", 0, 0};
-
-struct complaint range_type_base_complaint =
-  {"base type %d of range type is not defined", 0, 0};
 \f
-/* Support for Sun changes to dbx symbol format */
-
-/* For each identified header file, we have a table of types defined
-   in that header file.
-
-   header_files maps header file names to their type tables.
-   It is a vector of n_header_files elements.
-   Each element describes one header file.
-   It contains a vector of types.
-
-   Sometimes it can happen that the same header file produces
-   different results when included in different places.
-   This can result from conditionals or from different
-   things done before including the file.
-   When this happens, there are multiple entries for the file in this table,
-   one entry for each distinct set of results.
-   The entries are distinguished by the INSTANCE field.
-   The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is
-   used to match header-file references to their corresponding data.  */
-
-struct header_file
-{
-  char *name;                  /* Name of header file */
-  int instance;                        /* Numeric code distinguishing instances
-                                  of one header file that produced
-                                  different results when included.
-                                  It comes from the N_BINCL or N_EXCL.  */
-  struct type **vector;                /* Pointer to vector of types */
-  int length;                  /* Allocated length (# elts) of that vector */
-};
-
-static struct header_file *header_files = 0;
-
-static int n_header_files;
-
-static int n_allocated_header_files;
-
 /* During initial symbol readin, we need to have a structure to keep
    track of which psymtabs have which bincls in them.  This structure
    is used during readin to setup the list of dependencies within each
@@ -490,22 +184,6 @@ struct header_file_location
 static struct header_file_location *bincl_list, *next_bincl;
 static int bincls_allocated;
 
-/* Within each object file, various header files are assigned numbers.
-   A type is defined or referred to with a pair of numbers
-   (FILENUM,TYPENUM) where FILENUM is the number of the header file
-   and TYPENUM is the number within that header file.
-   TYPENUM is the index within the vector of types for that header file.
-
-   FILENUM == 1 is special; it refers to the main source of the object file,
-   and not to any header file.  FILENUM != 1 is interpreted by looking it up
-   in the following table, which contains indices in header_files.  */
-
-static int *this_object_header_files = 0;
-
-static int n_this_object_header_files;
-
-static int n_allocated_this_object_header_files;
-
 /* When a header file is getting special overriding definitions
    for one source file, record here the header_files index
    of its normal definition vector.
@@ -516,7 +194,7 @@ static int header_file_prev_index;
 /* Free up old header file tables, and allocate new ones.
    We're reading a new symbol file now.  */
 
-static void
+void
 free_and_init_header_files ()
 {
   register int i;
@@ -538,7 +216,7 @@ free_and_init_header_files ()
 /* Called at the start of each object file's symbols.
    Clear out the mapping of header file numbers to header files.  */
 
-static void
+void
 new_object_header_files ()
 {
   /* Leave FILENUM of 0 free for builtin types and this file's types.  */
@@ -630,115 +308,6 @@ add_new_header_file (name, instance)
   add_this_object_header_file (i);
 }
 
-/* Look up a dbx type-number pair.  Return the address of the slot
-   where the type for that number-pair is stored.
-   The number-pair is in TYPENUMS.
-
-   This can be used for finding the type associated with that pair
-   or for associating a new type with the pair.  */
-
-static struct type **
-dbx_lookup_type (typenums)
-     int typenums[2];
-{
-  register int filenum = typenums[0], index = typenums[1];
-
-  if (filenum < 0 || filenum >= n_this_object_header_files)
-    error ("Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
-          filenum, index, symnum);
-
-  if (filenum == 0)
-    {
-      /* Type is defined outside of header files.
-        Find it in this object file's type vector.  */
-      while (index >= type_vector_length)
-       {
-         type_vector_length *= 2;
-         type_vector = (struct type **)
-           xrealloc (type_vector,
-                     (type_vector_length * sizeof (struct type *)));
-         bzero (&type_vector[type_vector_length / 2],
-                type_vector_length * sizeof (struct type *) / 2);
-       }
-      return &type_vector[index];
-    }
-  else
-    {
-      register int real_filenum = this_object_header_files[filenum];
-      register struct header_file *f;
-      int f_orig_length;
-
-      if (real_filenum >= n_header_files)
-       abort ();
-
-      f = &header_files[real_filenum];
-
-      f_orig_length = f->length;
-      if (index >= f_orig_length)
-       {
-         while (index >= f->length)
-           f->length *= 2;
-         f->vector = (struct type **)
-           xrealloc (f->vector, f->length * sizeof (struct type *));
-         bzero (&f->vector[f_orig_length],
-                (f->length - f_orig_length) * sizeof (struct type *));
-       }
-      return &f->vector[index];
-    }
-}
-
-/* Create a type object.  Occaisionally used when you need a type
-   which isn't going to be given a type number.  */
-
-static struct type *
-dbx_create_type ()
-{
-  register struct type *type =
-    (struct type *) obstack_alloc (symbol_obstack, sizeof (struct type));
-
-  bzero (type, sizeof (struct type));
-  TYPE_VPTR_FIELDNO (type) = -1;
-  TYPE_VPTR_BASETYPE (type) = 0;
-  return type;
-}
-
-/* Make sure there is a type allocated for type numbers TYPENUMS
-   and return the type object.
-   This can create an empty (zeroed) type object.
-   TYPENUMS may be (-1, -1) to return a new type object that is not
-   put into the type vector, and so may not be referred to by number. */
-
-static struct type *
-dbx_alloc_type (typenums)
-     int typenums[2];
-{
-  register struct type **type_addr;
-  register struct type *type;
-
-  if (typenums[1] != -1)
-    {
-      type_addr = dbx_lookup_type (typenums);
-      type = *type_addr;
-    }
-  else
-    {
-      type_addr = 0;
-      type = 0;
-    }
-
-  /* If we are referring to a type not known at all yet,
-     allocate an empty type for it.
-     We will fill it in later if we find out how.  */
-  if (type == 0)
-    {
-      type = dbx_create_type ();
-      if (type_addr)
-       *type_addr = type;
-    }
-  
-  return type;
-}
-
 #if 0
 static struct type **
 explicit_lookup_type (real_filenum, index)
@@ -758,469 +327,80 @@ explicit_lookup_type (real_filenum, index)
 }
 #endif
 \f
-/* maintain the lists of symbols and blocks */
-
-/* Add a symbol to one of the lists of symbols.  */
-static void
-add_symbol_to_list (symbol, listhead)
-     struct symbol *symbol;
-     struct pending **listhead;
-{
-  /* We keep PENDINGSIZE symbols in each link of the list.
-     If we don't have a link with room in it, add a new link.  */
-  if (*listhead == 0 || (*listhead)->nsyms == PENDINGSIZE)
-    {
-      register struct pending *link;
-      if (free_pendings)
-       {
-         link = free_pendings;
-         free_pendings = link->next;
-       }
-      else
-       link = (struct pending *) xmalloc (sizeof (struct pending));
-
-      link->next = *listhead;
-      *listhead = link;
-      link->nsyms = 0;
-    }
-
-  (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
-}
-
-/* At end of reading syms, or in case of quit,
-   really free as many `struct pending's as we can easily find.  */
+/* Handle an N_SOL symbol, which indicates the start of
+   code that came from an included (or otherwise merged-in)
+   source file with a different name.  */
 
-/* ARGSUSED */
-static void
-really_free_pendings (foo)
-     int foo;
+void
+start_subfile (name, dirname)
+     char *name;
+     char *dirname;
 {
-  struct pending *next, *next1;
-#if 0
-  struct pending_block *bnext, *bnext1;
-#endif
+  register struct subfile *subfile;
 
-  for (next = free_pendings; next; next = next1)
-    {
-      next1 = next->next;
-      free (next);
-    }
-  free_pendings = 0;
+  /* Save the current subfile's line vector data.  */
 
-#if 0 /* Now we make the links in the symbol_obstack, so don't free them.  */
-  for (bnext = pending_blocks; bnext; bnext = bnext1)
+  if (current_subfile)
     {
-      bnext1 = bnext->next;
-      free (bnext);
+      current_subfile->line_vector_index = line_vector_index;
+      current_subfile->line_vector_length = line_vector_length;
+      current_subfile->prev_line_number = prev_line_number;
     }
-#endif
-  pending_blocks = 0;
 
-  for (next = file_symbols; next; next = next1)
-    {
-      next1 = next->next;
-      free (next);
-    }
-  file_symbols = 0;
+  /* See if this subfile is already known as a subfile of the
+     current main source file.  */
 
-  for (next = global_symbols; next; next = next1)
+  for (subfile = subfiles; subfile; subfile = subfile->next)
     {
-      next1 = next->next;
-      free (next);
+      if (!strcmp (subfile->name, name))
+       {
+         line_vector = subfile->line_vector;
+         line_vector_index = subfile->line_vector_index;
+         line_vector_length = subfile->line_vector_length;
+         prev_line_number = subfile->prev_line_number;
+         current_subfile = subfile;
+         return;
+       }
     }
-  global_symbols = 0;
-}
-
-/* Take one of the lists of symbols and make a block from it.
-   Keep the order the symbols have in the list (reversed from the input file).
-   Put the block on the list of pending blocks.  */
 
-static void
-finish_block (symbol, listhead, old_blocks, start, end)
-     struct symbol *symbol;
-     struct pending **listhead;
-     struct pending_block *old_blocks;
-     CORE_ADDR start, end;
-{
-  register struct pending *next, *next1;
-  register struct block *block;
-  register struct pending_block *pblock;
-  struct pending_block *opblock;
-  register int i;
-
-  /* Count the length of the list of symbols.  */
-
-  for (next = *listhead, i = 0; next; i += next->nsyms, next = next->next)
-    /*EMPTY*/;
-
-  block = (struct block *) obstack_alloc (symbol_obstack,
-                                         (sizeof (struct block)
-                                          + ((i - 1)
-                                             * sizeof (struct symbol *))));
-
-  /* Copy the symbols into the block.  */
-
-  BLOCK_NSYMS (block) = i;
-  for (next = *listhead; next; next = next->next)
-    {
-      register int j;
-      for (j = next->nsyms - 1; j >= 0; j--)
-       BLOCK_SYM (block, --i) = next->symbol[j];
-    }
+  /* This subfile is not known.  Add an entry for it.  */
 
-  BLOCK_START (block) = start;
-  BLOCK_END (block) = end;
-  BLOCK_SUPERBLOCK (block) = 0;        /* Filled in when containing block is made */
-  BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
+  line_vector_index = 0;
+  line_vector_length = 1000;
+  prev_line_number = -2;       /* Force first line number to be explicit */
+  line_vector = (struct linetable *)
+    xmalloc (sizeof (struct linetable)
+             + line_vector_length * sizeof (struct linetable_entry));
 
-  /* Put the block in as the value of the symbol that names it.  */
+  /* Make an entry for this subfile in the list of all subfiles
+     of the current main source file.  */
 
-  if (symbol)
-    {
-      SYMBOL_BLOCK_VALUE (symbol) = block;
-      BLOCK_FUNCTION (block) = symbol;
-    }
+  subfile = (struct subfile *) xmalloc (sizeof (struct subfile));
+  subfile->next = subfiles;
+  subfile->name = obsavestring (name, strlen (name));
+  if (dirname == NULL)
+    subfile->dirname = NULL;
   else
-    BLOCK_FUNCTION (block) = 0;
-
-  /* Now "free" the links of the list, and empty the list.  */
+    subfile->dirname = obsavestring (dirname, strlen (dirname));
+  
+  subfile->line_vector = line_vector;
+  subfiles = subfile;
+  current_subfile = subfile;
+}
+\f
+/* Handle the N_BINCL and N_EINCL symbol types
+   that act like N_SOL for switching source files
+   (different subfiles, as we call them) within one object file,
+   but using a stack rather than in an arbitrary order.  */
 
-  for (next = *listhead; next; next = next1)
-    {
-      next1 = next->next;
-      next->next = free_pendings;
-      free_pendings = next;
-    }
-  *listhead = 0;
+struct subfile_stack
+{
+  struct subfile_stack *next;
+  char *name;
+  int prev_index;
+};
 
-  /* Install this block as the superblock
-     of all blocks made since the start of this scope
-     that don't have superblocks yet.  */
-
-  opblock = 0;
-  for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
-    {
-      if (BLOCK_SUPERBLOCK (pblock->block) == 0) {
-#if 1
-       /* Check to be sure the blocks are nested as we receive them. 
-          If the compiler/assembler/linker work, this just burns a small
-          amount of time.  */
-       if (BLOCK_START (pblock->block) < BLOCK_START (block)
-        || BLOCK_END   (pblock->block) > BLOCK_END   (block)) {
-         complain(&innerblock_complaint, symbol? SYMBOL_NAME (symbol):
-                                                "(don't know)");
-         BLOCK_START (pblock->block) = BLOCK_START (block);
-         BLOCK_END   (pblock->block) = BLOCK_END   (block);
-       }
-#endif
-       BLOCK_SUPERBLOCK (pblock->block) = block;
-      }
-      opblock = pblock;
-    }
-
-  /* Record this block on the list of all blocks in the file.
-     Put it after opblock, or at the beginning if opblock is 0.
-     This puts the block in the list after all its subblocks.  */
-
-  /* Allocate in the symbol_obstack to save time.
-     It wastes a little space.  */
-  pblock = (struct pending_block *)
-    obstack_alloc (symbol_obstack,
-                  sizeof (struct pending_block));
-  pblock->block = block;
-  if (opblock)
-    {
-      pblock->next = opblock->next;
-      opblock->next = pblock;
-    }
-  else
-    {
-      pblock->next = pending_blocks;
-      pending_blocks = pblock;
-    }
-}
-
-static struct blockvector *
-make_blockvector ()
-{
-  register struct pending_block *next;
-  register struct blockvector *blockvector;
-  register int i;
-
-  /* Count the length of the list of blocks.  */
-
-  for (next = pending_blocks, i = 0; next; next = next->next, i++);
-
-  blockvector = (struct blockvector *)
-    obstack_alloc (symbol_obstack,
-                  (sizeof (struct blockvector)
-                   + (i - 1) * sizeof (struct block *)));
-
-  /* Copy the blocks into the blockvector.
-     This is done in reverse order, which happens to put
-     the blocks into the proper order (ascending starting address).
-     finish_block has hair to insert each block into the list
-     after its subblocks in order to make sure this is true.  */
-
-  BLOCKVECTOR_NBLOCKS (blockvector) = i;
-  for (next = pending_blocks; next; next = next->next) {
-    BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
-  }
-
-#if 0 /* Now we make the links in the obstack, so don't free them.  */
-  /* Now free the links of the list, and empty the list.  */
-
-  for (next = pending_blocks; next; next = next1)
-    {
-      next1 = next->next;
-      free (next);
-    }
-#endif
-  pending_blocks = 0;
-
-#if 1  /* FIXME, shut this off after a while to speed up symbol reading.  */
-  /* Some compilers output blocks in the wrong order, but we depend
-     on their being in the right order so we can binary search. 
-     Check the order and moan about it.  FIXME.  */
-  if (BLOCKVECTOR_NBLOCKS (blockvector) > 1)
-    for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++) {
-      if (BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i-1))
-         > BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i))) {
-       complain (&blockvector_complaint, 
-         BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i)));
-      }
-    }
-#endif
-
-  return blockvector;
-}
-\f
-/* Manage the vector of line numbers.  */
-
-static void
-record_line (line, pc)
-     int line;
-     CORE_ADDR pc;
-{
-  struct linetable_entry *e;
-  /* Ignore the dummy line number in libg.o */
-
-  if (line == 0xffff)
-    return;
-
-  /* Make sure line vector is big enough.  */
-
-  if (line_vector_index + 1 >= line_vector_length)
-    {
-      line_vector_length *= 2;
-      line_vector = (struct linetable *)
-       xrealloc (line_vector,
-                 (sizeof (struct linetable)
-                  + line_vector_length * sizeof (struct linetable_entry)));
-      current_subfile->line_vector = line_vector;
-    }
-
-  e = line_vector->item + line_vector_index++;
-  e->line = line; e->pc = pc;
-}
-\f
-/* Start a new symtab for a new source file.
-   This is called when a dbx symbol of type N_SO is seen;
-   it indicates the start of data for one original source file.  */
-
-static void
-start_symtab (name, dirname, start_addr)
-     char *name;
-     char *dirname;
-     CORE_ADDR start_addr;
-{
-
-  last_source_file = name;
-  last_source_start_addr = start_addr;
-  file_symbols = 0;
-  global_symbols = 0;
-  within_function = 0;
-
-  /* Context stack is initially empty, with room for 10 levels.  */
-  context_stack
-    = (struct context_stack *) xmalloc (10 * sizeof (struct context_stack));
-  context_stack_size = 10;
-  context_stack_depth = 0;
-
-  new_object_header_files ();
-
-  type_vector_length = 160;
-  type_vector = (struct type **)
-    xmalloc (type_vector_length * sizeof (struct type *));
-  bzero (type_vector, type_vector_length * sizeof (struct type *));
-
-  /* Initialize the list of sub source files with one entry
-     for this file (the top-level source file).  */
-
-  subfiles = 0;
-  current_subfile = 0;
-  start_subfile (name, dirname);
-}
-
-/* Handle an N_SOL symbol, which indicates the start of
-   code that came from an included (or otherwise merged-in)
-   source file with a different name.  */
-
-static void
-start_subfile (name, dirname)
-     char *name;
-     char *dirname;
-{
-  register struct subfile *subfile;
-
-  /* Save the current subfile's line vector data.  */
-
-  if (current_subfile)
-    {
-      current_subfile->line_vector_index = line_vector_index;
-      current_subfile->line_vector_length = line_vector_length;
-      current_subfile->prev_line_number = prev_line_number;
-    }
-
-  /* See if this subfile is already known as a subfile of the
-     current main source file.  */
-
-  for (subfile = subfiles; subfile; subfile = subfile->next)
-    {
-      if (!strcmp (subfile->name, name))
-       {
-         line_vector = subfile->line_vector;
-         line_vector_index = subfile->line_vector_index;
-         line_vector_length = subfile->line_vector_length;
-         prev_line_number = subfile->prev_line_number;
-         current_subfile = subfile;
-         return;
-       }
-    }
-
-  /* This subfile is not known.  Add an entry for it.  */
-
-  line_vector_index = 0;
-  line_vector_length = 1000;
-  prev_line_number = -2;       /* Force first line number to be explicit */
-  line_vector = (struct linetable *)
-    xmalloc (sizeof (struct linetable)
-             + line_vector_length * sizeof (struct linetable_entry));
-
-  /* Make an entry for this subfile in the list of all subfiles
-     of the current main source file.  */
-
-  subfile = (struct subfile *) xmalloc (sizeof (struct subfile));
-  subfile->next = subfiles;
-  subfile->name = obsavestring (name, strlen (name));
-  if (dirname == NULL)
-    subfile->dirname = NULL;
-  else
-    subfile->dirname = obsavestring (dirname, strlen (dirname));
-  
-  subfile->line_vector = line_vector;
-  subfiles = subfile;
-  current_subfile = subfile;
-}
-
-/* Finish the symbol definitions for one main source file,
-   close off all the lexical contexts for that file
-   (creating struct block's for them), then make the struct symtab
-   for that file and put it in the list of all such.
-
-   END_ADDR is the address of the end of the file's text.  */
-
-static struct symtab *
-end_symtab (end_addr)
-     CORE_ADDR end_addr;
-{
-  register struct symtab *symtab;
-  register struct blockvector *blockvector;
-  register struct subfile *subfile;
-  register struct linetable *lv;
-  struct subfile *nextsub;
-
-  /* Finish the lexical context of the last function in the file;
-     pop the context stack.  */
-
-  if (context_stack_depth > 0)
-    {
-      register struct context_stack *cstk;
-      context_stack_depth--;
-      cstk = &context_stack[context_stack_depth];
-      /* Make a block for the local symbols within.  */
-      finish_block (cstk->name, &local_symbols, cstk->old_blocks,
-                   cstk->start_addr, end_addr);
-    }
-
-  /* Cleanup any undefined types that have been left hanging around
-     (this needs to be done before the finish_blocks so that
-     file_symbols is still good).  */
-  cleanup_undefined_types ();
-
-  /* Define the STATIC_BLOCK and GLOBAL_BLOCK, and build the blockvector.  */
-  finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr);
-  finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr);
-  blockvector = make_blockvector ();
-
-  current_subfile->line_vector_index = line_vector_index;
-
-  /* Now create the symtab objects proper, one for each subfile.  */
-  /* (The main file is the last one on the chain.)  */
-
-  for (subfile = subfiles; subfile; subfile = nextsub)
-    {
-      symtab = allocate_symtab (subfile->name);
-
-      /* Fill in its components.  */
-      symtab->blockvector = blockvector;
-      lv = subfile->line_vector;
-      lv->nitems = subfile->line_vector_index;
-      symtab->linetable = (struct linetable *)
-       xrealloc (lv, (sizeof (struct linetable)
-                      + lv->nitems * sizeof (struct linetable_entry)));
-
-      symtab->dirname = subfile->dirname;
-
-      symtab->free_code = free_linetable;
-      symtab->free_ptr = 0;
-
-      /* There should never already be a symtab for this name, since
-        any prev dups have been removed when the psymtab was read in.
-        FIXME, there ought to be a way to check this here.  */
-      /* FIXME blewit |= free_named_symtabs (symtab->filename);  */
-
-      /* Link the new symtab into the list of such.  */
-      symtab->next = symtab_list;
-      symtab_list = symtab;
-
-      nextsub = subfile->next;
-      free (subfile);
-    }
-
-  free ((char *) type_vector);
-  type_vector = 0;
-  type_vector_length = -1;
-  line_vector = 0;
-  line_vector_length = -1;
-  last_source_file = 0;
-
-  return symtab;
-}
-\f
-/* Handle the N_BINCL and N_EINCL symbol types
-   that act like N_SOL for switching source files
-   (different subfiles, as we call them) within one object file,
-   but using a stack rather than in an arbitrary order.  */
-
-struct subfile_stack
-{
-  struct subfile_stack *next;
-  char *name;
-  int prev_index;
-};
-
-struct subfile_stack *subfile_stack;
+struct subfile_stack *subfile_stack;
 
 static void
 push_subfile ()
@@ -1276,11 +456,6 @@ record_misc_function (name, address, type)
                             address, misc_type);
 }
 \f
-/* The BFD for this file -- only good while we're actively reading
-   symbols into a psymtab or a symtab.  */
-
-static bfd *symfile_bfd;
-
 /* Scan and build partial symbols for a symbol file.
    We have been initialized by a call to dbx_symfile_init, which 
    put all the relevant info into a "struct dbx_symfile_info"
@@ -1364,12 +539,7 @@ dbx_symfile_read (sf, addr, mainline)
 static void
 dbx_new_init ()
 {
-  /* Empty the hash table of global syms looking for values.  */
-  bzero (global_sym_chain, sizeof global_sym_chain);
-
-  free_pendings = 0;
-  file_symbols = 0;
-  global_symbols = 0;
+  buildsym_new_init ();
 
   /* Don't put these on the cleanup chain; they need to stick around
      until the next call to dbx_new_init.  *Then* we'll free them. */
@@ -1409,7 +579,7 @@ dbx_symfile_init (sf)
   unsigned char size_temp[4];
 
   /* Allocate struct to keep track of the symfile */
-  sf->sym_private = xmalloc (sizeof (*info));   /* FIXME storage leak */
+  sf->sym_private = xmalloc (sizeof (*info));
   info = (struct dbx_symfile_info *)sf->sym_private;
 
   /* FIXME POKING INSIDE BFD DATA STRUCTURES */
@@ -1513,7 +683,7 @@ fill_symbuf ()
    (a \ at the end of the text of a name)
    call this function to get the continuation.  */
 
-static char *
+char *
 next_symbol_text ()
 {
   if (symbuf_idx == symbuf_end)
@@ -2592,10 +1762,7 @@ psymtab_to_symtab_1 (pst, desc, stringtab, stringtab_size, sym_offset)
   if (LDSYMLEN(pst))           /* Otherwise it's a dummy */
     {
       /* Init stuff necessary for reading in symbols */
-      free_pendings = 0;
-      pending_blocks = 0;
-      file_symbols = 0;
-      global_symbols = 0;
+      buildsym_init ();
       old_chain = make_cleanup (really_free_pendings, 0);
 
       /* Read in this files symbols */
@@ -2736,65 +1903,6 @@ dbx_psymtab_to_symtab (pst)
     }
 }
 
-/*
- * Scan through all of the global symbols defined in the object file,
- * assigning values to the debugging symbols that need to be assigned
- * to.  Get these symbols from the misc function list.
- */
-static void
-scan_file_globals ()
-{
-  int hash;
-  int mf;
-
-  for (mf = 0; mf < misc_function_count; mf++)
-    {
-      char *namestring = misc_function_vector[mf].name;
-      struct symbol *sym, *prev;
-
-      QUIT;
-
-      prev = (struct symbol *) 0;
-
-      /* Get the hash index and check all the symbols
-        under that hash index. */
-
-      hash = hashname (namestring);
-
-      for (sym = global_sym_chain[hash]; sym;)
-       {
-         if (*namestring == SYMBOL_NAME (sym)[0]
-             && !strcmp(namestring + 1, SYMBOL_NAME (sym) + 1))
-           {
-             /* Splice this symbol out of the hash chain and
-                assign the value we have to it. */
-             if (prev)
-               SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym);
-             else
-               global_sym_chain[hash] = SYMBOL_VALUE_CHAIN (sym);
-             
-             /* Check to see whether we need to fix up a common block.  */
-             /* Note: this code might be executed several times for
-                the same symbol if there are multiple references.  */
-             if (SYMBOL_CLASS (sym) == LOC_BLOCK)
-               fix_common_block (sym, misc_function_vector[mf].address);
-             else
-               SYMBOL_VALUE_ADDRESS (sym) = misc_function_vector[mf].address;
-             
-             if (prev)
-               sym = SYMBOL_VALUE_CHAIN (prev);
-             else
-               sym = global_sym_chain[hash];
-           }
-         else
-           {
-             prev = sym;
-             sym = SYMBOL_VALUE_CHAIN (sym);
-           }
-       }
-    }
-}
-
 /* Process a pair of symbols.  Currently they must both be N_SO's.  */
 /* ARGSUSED */
 static void
@@ -2902,17 +2010,20 @@ read_ofile_symtab (desc, stringtab, stringtab_size, sym_offset,
       bufp = &symbuf[symbuf_idx++];
       SWAP_SYMBOL (bufp);
 
-      type = bufp->n_type & N_TYPE;
+      type = bufp->n_type;
       if (type == (unsigned char)N_CATCH)
        {
          /* N_CATCH is not fixed up by the linker, and unfortunately,
             there's no other place to put it in the .stab map.  */
          bufp->n_value += text_offset + offset;
        }
-      else if (type == N_TEXT || type == N_DATA || type == N_BSS)
-       bufp->n_value += offset;
+      else {
+        type &= ~N_EXT;                /* Ignore external-bit */
+        if (type == N_TEXT || type == N_DATA || type == N_BSS)
+         bufp->n_value += offset;
+        type = bufp->n_type;
+      }
 
-      type = bufp->n_type;
       SET_NAMESTRING ();
 
       if (type & N_STAB)
@@ -2975,7 +2086,7 @@ read_ofile_symtab (desc, stringtab, stringtab_size, sym_offset,
   return end_symtab (text_offset + text_size);
 }
 \f
-static int
+int
 hashname (name)
      char *name;
 {
@@ -3276,30 +2387,6 @@ process_one_symbol (type, desc, valu, name)
     }
 }
 \f
-/* Read a number by which a type is referred to in dbx data,
-   or perhaps read a pair (FILENUM, TYPENUM) in parentheses.
-   Just a single number N is equivalent to (0,N).
-   Return the two numbers by storing them in the vector TYPENUMS.
-   TYPENUMS will then be used as an argument to dbx_lookup_type.  */
-
-static void
-read_type_number (pp, typenums)
-     register char **pp;
-     register int *typenums;
-{
-  if (**pp == '(')
-    {
-      (*pp)++;
-      typenums[0] = read_number (pp, ',');
-      typenums[1] = read_number (pp, ')');
-    }
-  else
-    {
-      typenums[0] = 0;
-      typenums[1] = read_number (pp, 0);
-    }
-}
-\f
 /* To handle GNU C++ typename abbreviation, we need to be able to
    fill in a type's name as soon as space for that type is allocated.
    `type_synonym_name' is the name of the type being allocated.
@@ -3723,449 +2810,34 @@ define_symbol (valu, string, desc, type)
   return sym;
 }
 \f
-/* What about types defined as forward references inside of a small lexical
-   scope?  */
-/* Add a type to the list of undefined types to be checked through
-   once this file has been read in.  */
-static void
-add_undefined_type (type)
-     struct type *type;
-{
-  if (undef_types_length == undef_types_allocated)
-    {
-      undef_types_allocated *= 2;
-      undef_types = (struct type **)
-       xrealloc (undef_types,
-                 undef_types_allocated * sizeof (struct type *));
-    }
-  undef_types[undef_types_length++] = type;
-}
-
-/* Add here something to go through each undefined type, see if it's
-   still undefined, and do a full lookup if so.  */
-static void
-cleanup_undefined_types ()
-{
-  struct type **type;
-
-  for (type = undef_types; type < undef_types + undef_types_length; type++)
-    {
-      /* Reasonable test to see if it's been defined since.  */
-      if (TYPE_NFIELDS (*type) == 0)
-       {
-         struct pending *ppt;
-         int i;
-         /* Name of the type, without "struct" or "union" */
-         char *typename = TYPE_NAME (*type);
-
-         if (!strncmp (typename, "struct ", 7))
-           typename += 7;
-         if (!strncmp (typename, "union ", 6))
-           typename += 6;
-
-         for (ppt = file_symbols; ppt; ppt = ppt->next)
-           for (i = 0; i < ppt->nsyms; i++)
-             {
-               struct symbol *sym = ppt->symbol[i];
-
-               if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
-                   && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
-                   && (TYPE_CODE (SYMBOL_TYPE (sym)) ==
-                       TYPE_CODE (*type))
-                   && !strcmp (SYMBOL_NAME (sym), typename))
-                 bcopy (SYMBOL_TYPE (sym), *type, sizeof (struct type));
-             }
-       }
-      else
-       /* It has been defined; don't mark it as a stub.  */
-       TYPE_FLAGS (*type) &= ~TYPE_FLAG_STUB;
-    }
-  undef_types_length = 0;
-}
-
-/* Skip rest of this symbol and return an error type.
-
-   General notes on error recovery:  error_type always skips to the
-   end of the symbol (modulo cretinous dbx symbol name continuation).
-   Thus code like this:
-
-   if (*(*pp)++ != ';')
-     return error_type (pp);
-
-   is wrong because if *pp starts out pointing at '\0' (typically as the
-   result of an earlier error), it will be incremented to point to the
-   start of the next symbol, which might produce strange results, at least
-   if you run off the end of the string table.  Instead use
-
-   if (**pp != ';')
-     return error_type (pp);
-   ++*pp;
+#if 0
+/* This would be a good idea, but it doesn't really work.  The problem
+   is that in order to get the virtual context for a particular type,
+   you need to know the virtual info from all of its basetypes,
+   and you need to have processed its methods.  Since GDB reads
+   symbols on a file-by-file basis, this means processing the symbols
+   of all the files that are needed for each baseclass, which
+   means potentially reading in all the debugging info just to fill
+   in information we may never need.  */
 
-   or
+/* This page contains subroutines of read_type.  */
 
-   if (**pp != ';')
-     foo = error_type (pp);
-   else
-     ++*pp;
+/* FOR_TYPE is a struct type defining a virtual function NAME with type
+   FN_TYPE.  The `virtual context' for this virtual function is the
+   first base class of FOR_TYPE in which NAME is defined with signature
+   matching FN_TYPE.  OFFSET serves as a hash on matches here.
 
-   And in case it isn't obvious, the point of all this hair is so the compiler
-   can define new types and new syntaxes, and old versions of the
-   debugger will be able to read the new symbol tables.  */
+   TYPE is the current type in which we are searching.  */
 
 static struct type *
-error_type (pp)
-     char **pp;
+virtual_context (for_type, type, name, fn_type, offset)
+     struct type *for_type, *type;
+     char *name;
+     struct type *fn_type;
+     int offset;
 {
-  complain (&error_type_complaint, 0);
-  while (1)
-    {
-      /* Skip to end of symbol.  */
-      while (**pp != '\0')
-       (*pp)++;
-
-      /* Check for and handle cretinous dbx symbol name continuation!  */
-      if ((*pp)[-1] == '\\')
-       *pp = next_symbol_text ();
-      else
-       break;
-    }
-  return builtin_type_error;
-}
-\f
-/* Read a dbx type reference or definition;
-   return the type that is meant.
-   This can be just a number, in which case it references
-   a type already defined and placed in type_vector.
-   Or the number can be followed by an =, in which case
-   it means to define a new type according to the text that
-   follows the =.  */
-
-static
-struct type *
-read_type (pp)
-     register char **pp;
-{
-  register struct type *type = 0;
-  struct type *type1;
-  int typenums[2];
-  int xtypenums[2];
-
-  /* Read type number if present.  The type number may be omitted.
-     for instance in a two-dimensional array declared with type
-     "ar1;1;10;ar1;1;10;4".  */
-  if ((**pp >= '0' && **pp <= '9')
-      || **pp == '(')
-    {
-      read_type_number (pp, typenums);
-      
-      /* Detect random reference to type not yet defined.
-        Allocate a type object but leave it zeroed.  */
-      if (**pp != '=')
-       return dbx_alloc_type (typenums);
-
-      *pp += 2;
-    }
-  else
-    {
-      /* '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;
-    }
-      
-  switch ((*pp)[-1])
-    {
-    case 'x':
-      {
-       enum type_code code;
-
-       /* Used to index through file_symbols.  */
-       struct pending *ppt;
-       int i;
-       
-       /* Name including "struct", etc.  */
-       char *type_name;
-       
-       /* Name without "struct", etc.  */
-       char *type_name_only;
-
-       {
-         char *prefix;
-         char *from, *to;
-         
-         /* Set the type code according to the following letter.  */
-         switch ((*pp)[0])
-           {
-           case 's':
-             code = TYPE_CODE_STRUCT;
-             prefix = "struct ";
-             break;
-           case 'u':
-             code = TYPE_CODE_UNION;
-             prefix = "union ";
-             break;
-           case 'e':
-             code = TYPE_CODE_ENUM;
-             prefix = "enum ";
-             break;
-           default:
-             return error_type (pp);
-           }
-         
-         to = type_name = (char *)
-           obstack_alloc (symbol_obstack,
-                          (strlen (prefix) +
-                           ((char *) strchr (*pp, ':') - (*pp)) + 1));
-       
-         /* Copy the prefix.  */
-         from = prefix;
-         while (*to++ = *from++)
-           ;
-         to--; 
-       
-         type_name_only = to;
-
-         /* Copy the name.  */
-         from = *pp + 1;
-         while ((*to++ = *from++) != ':')
-           ;
-         *--to = '\0';
-         
-         /* Set the pointer ahead of the name which we just read.  */
-         *pp = from;
-       
-#if 0
-         /* The following hack is clearly wrong, because it doesn't
-            check whether we are in a baseclass.  I tried to reproduce
-            the case that it is trying to fix, but I couldn't get
-            g++ to put out a cross reference to a basetype.  Perhaps
-            it doesn't do it anymore.  */
-         /* Note: for C++, the cross reference may be to a base type which
-            has not yet been seen.  In this case, we skip to the comma,
-            which will mark the end of the base class name.  (The ':'
-            at the end of the base class name will be skipped as well.)
-            But sometimes (ie. when the cross ref is the last thing on
-            the line) there will be no ','.  */
-         from = (char *) strchr (*pp, ',');
-         if (from)
-           *pp = from;
-#endif /* 0 */
-       }
-
-       /* Now check to see whether the type has already been declared.  */
-       /* This is necessary at least in the case where the
-          program says something like
-            struct foo bar[5];
-          The compiler puts out a cross-reference; we better find
-          set the length of the structure correctly so we can
-          set the length of the array.  */
-       for (ppt = file_symbols; ppt; ppt = ppt->next)
-         for (i = 0; i < ppt->nsyms; i++)
-           {
-             struct symbol *sym = ppt->symbol[i];
-
-             if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
-                 && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
-                 && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
-                 && !strcmp (SYMBOL_NAME (sym), type_name_only))
-               {
-                 obstack_free (symbol_obstack, type_name);
-                 type = SYMBOL_TYPE (sym);
-                 return type;
-               }
-           }
-       
-       /* Didn't find the type to which this refers, so we must
-          be dealing with a forward reference.  Allocate a type
-          structure for it, and keep track of it so we can
-          fill in the rest of the fields when we get the full
-          type.  */
-       type = dbx_alloc_type (typenums);
-       TYPE_CODE (type) = code;
-       TYPE_NAME (type) = type_name;
-
-       TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
-
-       add_undefined_type (type);
-       return type;
-      }
-
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-    case '(':
-      (*pp)--;
-      read_type_number (pp, xtypenums);
-      type = *dbx_lookup_type (xtypenums);
-      if (type == 0)
-       type = builtin_type_void;
-      if (typenums[0] != -1)
-       *dbx_lookup_type (typenums) = type;
-      break;
-
-    case '*':
-      type1 = read_type (pp);
-      type = lookup_pointer_type (type1);
-      if (typenums[0] != -1)
-       *dbx_lookup_type (typenums) = type;
-      break;
-
-    case '@':
-      {
-       struct type *domain = read_type (pp);
-       struct type *memtype;
-
-       if (**pp != ',')
-         /* Invalid member type data format.  */
-         return error_type (pp);
-       ++*pp;
-
-       memtype = read_type (pp);
-       type = dbx_alloc_type (typenums);
-       smash_to_member_type (type, domain, memtype);
-      }
-      break;
-
-    case '#':
-      if ((*pp)[0] == '#')
-       {
-         /* We'll get the parameter types from the name.  */
-         struct type *return_type;
-
-         *pp += 1;
-         return_type = read_type (pp);
-         if (*(*pp)++ != ';')
-           complain (&invalid_member_complaint, symnum);
-         type = allocate_stub_method (return_type);
-         if (typenums[0] != -1)
-           *dbx_lookup_type (typenums) = type;
-       }
-      else
-       {
-         struct type *domain = read_type (pp);
-         struct type *return_type;
-         struct type **args;
-
-         if (*(*pp)++ != ',')
-           error ("invalid member type data format, at symtab pos %d.",
-                  symnum);
-
-         return_type = read_type (pp);
-         args = read_args (pp, ';');
-         type = dbx_alloc_type (typenums);
-         smash_to_method_type (type, domain, return_type, args);
-       }
-      break;
-
-    case '&':
-      type1 = read_type (pp);
-      type = lookup_reference_type (type1);
-      if (typenums[0] != -1)
-       *dbx_lookup_type (typenums) = type;
-      break;
-
-    case 'f':
-      type1 = read_type (pp);
-      type = lookup_function_type (type1);
-      if (typenums[0] != -1)
-       *dbx_lookup_type (typenums) = type;
-      break;
-
-    case 'r':
-      type = read_range_type (pp, typenums);
-      if (typenums[0] != -1)
-       *dbx_lookup_type (typenums) = type;
-      break;
-
-    case 'e':
-      type = dbx_alloc_type (typenums);
-      type = read_enum_type (pp, type);
-      *dbx_lookup_type (typenums) = type;
-      break;
-
-    case 's':
-      type = dbx_alloc_type (typenums);
-      TYPE_NAME (type) = type_synonym_name;
-      type_synonym_name = 0;
-      type = read_struct_type (pp, type);
-      break;
-
-    case 'u':
-      type = dbx_alloc_type (typenums);
-      TYPE_NAME (type) = type_synonym_name;
-      type_synonym_name = 0;
-      type = read_struct_type (pp, type);
-      TYPE_CODE (type) = TYPE_CODE_UNION;
-      break;
-
-    case 'a':
-      if (**pp != 'r')
-       return error_type (pp);
-      ++*pp;
-      
-      type = dbx_alloc_type (typenums);
-      type = read_array_type (pp, type);
-      break;
-
-    default:
-      --*pp;                   /* Go back to the symbol in error */
-                               /* Particularly important if it was \0! */
-      return error_type (pp);
-    }
-
-  if (type == 0)
-    abort ();
-
-#if 0
-  /* If this is an overriding temporary alteration for a header file's
-     contents, and this type number is unknown in the global definition,
-     put this type into the global definition at this type number.  */
-  if (header_file_prev_index >= 0)
-    {
-      register struct type **tp
-        = explicit_lookup_type (header_file_prev_index, typenums[1]);
-      if (*tp == 0)
-       *tp = type;
-    }
-#endif
-  return type;
-}
-\f
-#if 0
-/* This would be a good idea, but it doesn't really work.  The problem
-   is that in order to get the virtual context for a particular type,
-   you need to know the virtual info from all of its basetypes,
-   and you need to have processed its methods.  Since GDB reads
-   symbols on a file-by-file basis, this means processing the symbols
-   of all the files that are needed for each baseclass, which
-   means potentially reading in all the debugging info just to fill
-   in information we may never need.  */
-
-/* This page contains subroutines of read_type.  */
-
-/* FOR_TYPE is a struct type defining a virtual function NAME with type
-   FN_TYPE.  The `virtual context' for this virtual function is the
-   first base class of FOR_TYPE in which NAME is defined with signature
-   matching FN_TYPE.  OFFSET serves as a hash on matches here.
-
-   TYPE is the current type in which we are searching.  */
-
-static struct type *
-virtual_context (for_type, type, name, fn_type, offset)
-     struct type *for_type, *type;
-     char *name;
-     struct type *fn_type;
-     int offset;
-{
-  struct type *basetype = 0;
-  int i;
+  struct type *basetype = 0;
+  int i;
 
   if (for_type != type)
     {
@@ -4195,1223 +2867,6 @@ virtual_context (for_type, type, name, fn_type, offset)
   return for_type;
 }
 #endif
-
-/* Read the description of a structure (or union type)
-   and return an object describing the type.  */
-
-static struct type *
-read_struct_type (pp, type)
-     char **pp;
-     register struct type *type;
-{
-  /* 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 total_length = 0;
-
-  struct nextfield
-    {
-      struct nextfield *next;
-      int visibility;                  /* 0=public, 1=protected, 2=public */
-      struct field field;
-    };
-
-  struct next_fnfield
-    {
-      struct next_fnfield *next;
-      int visibility;                  /* 0=public, 1=protected, 2=public */
-      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;
-  register char *p;
-  int nfields = 0;
-  register int n;
-
-  register struct next_fnfieldlist *mainlist = 0;
-  int nfn_fields = 0;
-
-  if (TYPE_MAIN_VARIANT (type) == 0)
-    {
-      TYPE_MAIN_VARIANT (type) = type;
-    }
-
-  TYPE_CODE (type) = TYPE_CODE_STRUCT;
-
-  /* First comes the total size in bytes.  */
-
-  TYPE_LENGTH (type) = read_number (pp, 0);
-
-  /* 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 == '!')
-    {
-      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;
-
-      n_baseclasses = read_number (pp, ',');
-      TYPE_FIELD_VIRTUAL_BITS (type) =
-         (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (n_baseclasses));
-      B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), n_baseclasses);
-
-      for (i = 0; i < n_baseclasses; i++)
-       {
-         if (**pp == '\\')
-           *pp = next_symbol_text ();
-
-         switch (**pp)
-           {
-           case '0':
-             via_virtual = 0;
-             break;
-           case '1':
-             via_virtual = 1;
-             break;
-           default:
-             /* Bad visibility format.  */
-             return error_type (pp);
-           }
-         ++*pp;
-
-         switch (**pp)
-           {
-           case '0':
-             via_public = 0;
-             break;
-           case '2':
-             via_public = 2;
-             break;
-           default:
-             /* Bad visibility format.  */
-             return error_type (pp);
-           }
-         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);
-         *pp += 1;             /* skip trailing ';' */
-
-         /* Make this baseclass visible for structure-printing purposes.  */
-         new = (struct nextfield *) alloca (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++;
-       }
-      TYPE_N_BASECLASSES (type) = n_baseclasses;
-    }
-
-  /* Now come the fields, as NAME:?TYPENUM,BITPOS,BITSIZE; for each one.
-     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 `?' is a placeholder for one of '/2' (public visibility),
-     '/1' (protected visibility), '/0' (private visibility), or nothing
-     (C style symbol table, public visibility).  */
-
-  /* We better set p right now, in case there are no fields at all...    */
-  p = *pp;
-
-  while (**pp != ';')
-    {
-      /* Check for and handle cretinous dbx symbol name continuation!  */
-      if (**pp == '\\') *pp = next_symbol_text ();
-
-      /* Get space to record the next field's data.  */
-      new = (struct nextfield *) alloca (sizeof (struct nextfield));
-      new->next = list;
-      list = new;
-
-      /* Get the field name.  */
-      p = *pp;
-      if (*p == CPLUS_MARKER)
-       {
-         /* Special GNU C++ name.  */
-         if (*++p == 'v')
-           {
-             const char *prefix;
-             char *name = 0;
-             struct type *context;
-
-             switch (*++p)
-               {
-               case 'f':
-                 prefix = vptr_name;
-                 break;
-               case 'b':
-                 prefix = vb_name;
-                 break;
-               default:
-                 error ("invalid abbreviation at symtab pos %d.", symnum);
-               }
-             *pp = p + 1;
-             context = read_type (pp);
-             if (type_name_no_tag (context) == 0)
-               {
-                 if (name == 0)
-                   error ("type name unknown at symtab pos %d.", symnum);
-                 /* FIXME-tiemann: when is `name' ever non-0?  */
-                 TYPE_NAME (context) = obsavestring (name, p - name - 1);
-               }
-             list->field.name = obconcat (prefix, type_name_no_tag (context), "");
-             p = ++(*pp);
-             if (p[-1] != ':')
-               error ("invalid abbreviation at symtab pos %d.", symnum);
-             list->field.type = read_type (pp);
-             (*pp)++;                  /* Skip the comma.  */
-             list->field.bitpos = read_number (pp, ';');
-             /* This field is unpacked.  */
-             list->field.bitsize = 0;
-           }
-         /* GNU C++ anonymous type.  */
-         else if (*p == '_')
-           break;
-         else
-           error ("invalid abbreviation at symtab pos %d.", symnum);
-
-         nfields++;
-         continue;
-       }
-
-      while (*p != ':') p++;
-      list->field.name = obsavestring (*pp, p - *pp);
-
-      /* C++: Check to see if we have hit the methods yet.  */
-      if (p[1] == ':')
-       break;
-
-      *pp = p + 1;
-
-      /* This means we have a visibility for a field coming. */
-      if (**pp == '/')
-       {
-         switch (*++*pp)
-           {
-           case '0':
-             list->visibility = 0;     /* private */
-             *pp += 1;
-             break;
-
-           case '1':
-             list->visibility = 1;     /* protected */
-             *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);
-      if (**pp == ':')
-       {
-         /* Static class member.  */
-         list->field.bitpos = (long)-1;
-         p = ++(*pp);
-         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);
-
-      (*pp)++;                 /* Skip the comma.  */
-      list->field.bitpos = read_number (pp, ',');
-      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 (list->field.bitpos == 0
-         && list->field.bitsize == 0)
-       {
-         complain (&dbx_class_complaint, 0);
-         /* Ignore this field.  */
-         list = 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 (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 (builtin_type_int))
-                  )
-              )
-             &&
-             list->field.bitpos % 8 == 0)
-           list->field.bitsize = 0;
-         nfields++;
-       }
-    }
-
-  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.  */
-
-  TYPE_NFIELDS (type) = nfields;
-  TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack,
-                                              sizeof (struct field) * nfields);
-
-  TYPE_FIELD_PRIVATE_BITS (type) =
-    (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (nfields));
-  B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
-
-  TYPE_FIELD_PROTECTED_BITS (type) =
-    (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (nfields));
-  B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
-
-  /* Copy the saved-up fields into the field vector.  */
-
-  for (n = nfields; list; list = list->next)
-    {
-      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);
-    }
-
-  /* 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.
-
-     For the case of overloaded operators, the format is
-     OPERATOR::*.methods, where OPERATOR is the string "operator",
-     `*' holds the place for an operator name (such as `+=')
-     and `.' marks the end of the operator name.  */
-  if (p[1] == ':')
-    {
-      /* Now, read in the methods.  To simplify matters, we
-        "unread" the name that has been read, so that we can
-        start from the top.  */
-
-      /* 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 =
-           (struct next_fnfieldlist *)alloca (sizeof (struct next_fnfieldlist));
-         char *main_fn_name;
-
-         p = *pp;
-
-         /* read in the name.  */
-         while (*p != ':') p++;
-         if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == CPLUS_MARKER)
-           {
-             /* 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 '::'.  */
-             p += 2;
-             while (*p != '.')
-               *o++ = *p++;
-            main_fn_name = savestring (opname, o - opname);
-             /* Skip past '.'  */
-             *pp = p + 1;
-           }
-         else
-           {
-             i = 0;
-             main_fn_name = savestring (*pp, p - *pp);
-             /* Skip past '::'.  */
-             *pp = p + 2;
-           }
-         new_mainlist->fn_fieldlist.name = main_fn_name;
-
-         do
-           {
-             struct next_fnfield *new_sublist =
-               (struct next_fnfield *)alloca (sizeof (struct next_fnfield));
-
-             /* Check for and handle cretinous dbx symbol name continuation!  */
-             if (look_ahead_type == NULL) /* Normal case. */
-               {
-                 if (**pp == '\\') *pp = next_symbol_text ();
-
-                 new_sublist->fn_field.type = read_type (pp);
-                 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.  */
-             new_sublist->fn_field.physname = savestring (*pp, p - *pp);
-             *pp = p + 1;
-             new_sublist->visibility = *(*pp)++ - '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;
-               default:
-                 /* This probably just means we're processing a file compiled
-                    with g++ version 1.  */
-                 complain(&const_vol_complaint, **pp);
-               }
-
-             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);
-                     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;
-                 break;
-               default:
-                 /* **pp == '.'.  */
-                 /* normal member function.  */
-                 new_sublist->fn_field.voffset = 0;
-                 new_sublist->fn_field.fcontext = 0;
-                 break;
-               }
-
-             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 (symbol_obstack,
-                                              sizeof (struct fn_field) * length);
-         TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist) =
-           (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (length));
-         B_CLRALL (TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist), length);
-
-         TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist) =
-           (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (length));
-         B_CLRALL (TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist), length);
-
-         for (i = length; (i--, sublist); sublist = sublist->next)
-           {
-             new_mainlist->fn_fieldlist.fn_fields[i] = sublist->fn_field;
-             if (sublist->visibility == 0)
-               B_SET (new_mainlist->fn_fieldlist.private_fn_field_bits, i);
-             else if (sublist->visibility == 1)
-               B_SET (new_mainlist->fn_fieldlist.protected_fn_field_bits, i);
-           }
-
-         new_mainlist->fn_fieldlist.length = length;
-         new_mainlist->next = mainlist;
-         mainlist = new_mainlist;
-         nfn_fields++;
-         total_length += length;
-       }
-      while (**pp != ';');
-    }
-
-  *pp += 1;
-
-  TYPE_FN_FIELDLISTS (type) =
-    (struct fn_fieldlist *) obstack_alloc (symbol_obstack,
-                                  sizeof (struct fn_fieldlist) * nfn_fields);
-
-  TYPE_NFN_FIELDS (type) = nfn_fields;
-  TYPE_NFN_FIELDS_TOTAL (type) = total_length;
-
-  {
-    int i;
-    for (i = 0; i < TYPE_N_BASECLASSES (type); ++i)
-      TYPE_NFN_FIELDS_TOTAL (type) +=
-       TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, i));
-  }
-
-  for (n = nfn_fields; mainlist; mainlist = mainlist->next)
-    TYPE_FN_FIELDLISTS (type)[--n] = mainlist->fn_fieldlist;
-
-  if (**pp == '~')
-    {
-      *pp += 1;
-
-      if (**pp == '=')
-       {
-         TYPE_FLAGS (type)
-           |= TYPE_FLAG_HAS_CONSTRUCTOR | TYPE_FLAG_HAS_DESTRUCTOR;
-         *pp += 1;
-       }
-      else if (**pp == '+')
-       {
-         TYPE_FLAGS (type) |= TYPE_FLAG_HAS_CONSTRUCTOR;
-         *pp += 1;
-       }
-      else if (**pp == '-')
-       {
-         TYPE_FLAGS (type) |= TYPE_FLAG_HAS_DESTRUCTOR;
-         *pp += 1;
-       }
-
-      /* Read either a '%' or the final ';'.  */
-      if (*(*pp)++ == '%')
-       {
-         /* Now we must record the virtual function table pointer's
-            field information.  */
-
-         struct type *t;
-         int i;
-
-         t = read_type (pp);
-         p = (*pp)++;
-         while (*p != '\0' && *p != ';')
-           p++;
-         if (*p == '\0')
-           /* Premature end of symbol.  */
-           return error_type (pp);
-         
-         TYPE_VPTR_BASETYPE (type) = t;
-         if (type == t)
-           {
-             if (TYPE_FIELD_NAME (t, TYPE_N_BASECLASSES (t)) == 0)
-               {
-                 /* FIXME-tiemann: what's this?  */
-#if 0
-                 TYPE_VPTR_FIELDNO (type) = i = TYPE_N_BASECLASSES (t);
-#else
-                 error_type (pp);
-#endif
-               }
-             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);
-           }
-         else
-           TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t);
-         *pp = p + 1;
-       }
-    }
-
-  return type;
-}
-
-/* Read a definition of an array type,
-   and create and return a suitable type object.
-   Also creates a range type which represents the bounds of that
-   array.  */
-static struct type *
-read_array_type (pp, type)
-     register char **pp;
-     register struct type *type;
-{
-  struct type *index_type, *element_type, *range_type;
-  int lower, upper;
-  int adjustable = 0;
-
-  /* Format of an array type:
-     "ar<index type>;lower;upper;<array_contents_type>".  Put code in
-     to handle this.
-
-     Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
-     for these, produce a type like float[][].  */
-
-  index_type = read_type (pp);
-  if (**pp != ';')
-    /* Improper format of array type decl.  */
-    return error_type (pp);
-  ++*pp;
-
-  if (!(**pp >= '0' && **pp <= '9'))
-    {
-      *pp += 1;
-      adjustable = 1;
-    }
-  lower = read_number (pp, ';');
-
-  if (!(**pp >= '0' && **pp <= '9'))
-    {
-      *pp += 1;
-      adjustable = 1;
-    }
-  upper = read_number (pp, ';');
-  
-  element_type = read_type (pp);
-
-  if (adjustable)
-    {
-      lower = 0;
-      upper = -1;
-    }
-
-  {
-    /* Create range type.  */
-    range_type = (struct type *) obstack_alloc (symbol_obstack,
-                                               sizeof (struct type));
-    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 (symbol_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 (symbol_obstack,
-                                   sizeof (struct field));
-  TYPE_FIELD_TYPE (type, 0) = range_type;
-
-  return type;
-}
-
-
-/* Read a definition of an enumeration type,
-   and create and return a suitable type object.
-   Also defines the symbols that represent the values of the type.  */
-
-static struct type *
-read_enum_type (pp, type)
-     register char **pp;
-     register struct type *type;
-{
-  register char *p;
-  char *name;
-  register long n;
-  register struct symbol *sym;
-  int nsyms = 0;
-  struct pending **symlist;
-  struct pending *osyms, *syms;
-  int o_nsyms;
-
-  if (within_function)
-    symlist = &local_symbols;
-  else
-    symlist = &file_symbols;
-  osyms = *symlist;
-  o_nsyms = osyms ? osyms->nsyms : 0;
-
-  /* Read the value-names and their values.
-     The input syntax is NAME:VALUE,NAME:VALUE, and so on.
-     A semicolon or comman 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 ();
-
-      p = *pp;
-      while (*p != ':') p++;
-      name = obsavestring (*pp, p - *pp);
-      *pp = p + 1;
-      n = read_number (pp, ',');
-
-      sym = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
-      bzero (sym, sizeof (struct symbol));
-      SYMBOL_NAME (sym) = name;
-      SYMBOL_CLASS (sym) = LOC_CONST;
-      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
-      SYMBOL_VALUE (sym) = n;
-      add_symbol_to_list (sym, symlist);
-      nsyms++;
-    }
-
-  if (**pp == ';')
-    (*pp)++;                   /* Skip the semicolon.  */
-
-  /* Now fill in the fields of the type-structure.  */
-
-  TYPE_LENGTH (type) = sizeof (int);
-  TYPE_CODE (type) = TYPE_CODE_ENUM;
-  TYPE_NFIELDS (type) = nsyms;
-  TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack, 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
-     to cause them to be defined.  osyms contains the old value
-     of that symlist; everything up to there was defined by us.  */
-  /* Note that we preserve the order of the enum constants, so
-     that in something like "enum {FOO, LAST_THING=FOO}" we print
-     FOO, not LAST_THING.  */
-
-  for (syms = *symlist, n = 0; syms; syms = syms->next)
-    {
-      int j = 0;
-      if (syms == osyms)
-       j = o_nsyms;
-      for (; j < syms->nsyms; j++,n++)
-       {
-         struct symbol *xsym = syms->symbol[j];
-         SYMBOL_TYPE (xsym) = type;
-         TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym);
-         TYPE_FIELD_VALUE (type, n) = 0;
-         TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
-         TYPE_FIELD_BITSIZE (type, n) = 0;
-       }
-      if (syms == osyms)
-       break;
-    }
-
-#if 0
-  /* 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"))))
-     TYPE_CODE(type) = TYPE_CODE_BOOL;
-#endif
-
-  return type;
-}
-
-/* Read a number from the string pointed to by *PP.
-   The value of *PP is advanced over the number.
-   If END is nonzero, the character that ends the
-   number must match END, or an error happens;
-   and that character is skipped if it does match.
-   If END is zero, *PP is left pointing to that character.
-
-   If the number fits in a long, set *VALUE and set *BITS to 0.
-   If not, set *BITS to be the number of bits in the number.
-
-   If encounter garbage, set *BITS to -1.  */
-
-static void
-read_huge_number (pp, end, valu, bits)
-     char **pp;
-     int end;
-     long *valu;
-     int *bits;
-{
-  char *p = *pp;
-  int sign = 1;
-  long n = 0;
-  int radix = 10;
-  char overflow = 0;
-  int nbits = 0;
-  int c;
-  long upper_limit;
-  
-  if (*p == '-')
-    {
-      sign = -1;
-      p++;
-    }
-
-  /* Leading zero means octal.  GCC uses this to output values larger
-     than an int (because that would be hard in decimal).  */
-  if (*p == '0')
-    {
-      radix = 8;
-      p++;
-    }
-
-  upper_limit = LONG_MAX / radix;
-  while ((c = *p++) >= '0' && c <= ('0' + radix))
-    {
-      if (n <= upper_limit)
-       {
-         n *= radix;
-         n += c - '0';         /* FIXME this overflows anyway */
-       }
-      else
-       overflow = 1;
-      
-      /* This depends on large values being output in octal, which is
-        what GCC does. */
-      if (radix == 8)
-       {
-         if (nbits == 0)
-           {
-             if (c == '0')
-               /* Ignore leading zeroes.  */
-               ;
-             else if (c == '1')
-               nbits = 1;
-             else if (c == '2' || c == '3')
-               nbits = 2;
-             else
-               nbits = 3;
-           }
-         else
-           nbits += 3;
-       }
-    }
-  if (end)
-    {
-      if (c && c != end)
-       {
-         if (bits != NULL)
-           *bits = -1;
-         return;
-       }
-    }
-  else
-    --p;
-
-  *pp = p;
-  if (overflow)
-    {
-      if (nbits == 0)
-       {
-         /* Large decimal constants are an error (because it is hard to
-            count how many bits are in them).  */
-         if (bits != NULL)
-           *bits = -1;
-         return;
-       }
-      
-      /* -0x7f is the same as 0x80.  So deal with it by adding one to
-        the number of bits.  */
-      if (sign == -1)
-       ++nbits;
-      if (bits)
-       *bits = nbits;
-    }
-  else
-    {
-      if (valu)
-       *valu = n * sign;
-      if (bits)
-       *bits = 0;
-    }
-}
-
-#define        MAX_OF_C_TYPE(t)        ((1 << (sizeof (t)*8 - 1)) - 1)
-#define MIN_OF_C_TYPE(t)       (-(1 << (sizeof (t)*8 - 1)))
-
-static struct type *
-read_range_type (pp, typenums)
-     char **pp;
-     int typenums[2];
-{
-  int rangenums[2];
-  long n2, n3;
-  int n2bits, n3bits;
-  int self_subrange;
-  struct type *result_type;
-
-  /* First comes a type we are a subrange of.
-     In C it is usually 0, 1 or the type being defined.  */
-  read_type_number (pp, rangenums);
-  self_subrange = (rangenums[0] == typenums[0] &&
-                  rangenums[1] == typenums[1]);
-
-  /* A semicolon should now follow; skip it.  */
-  if (**pp == ';')
-    (*pp)++;
-
-  /* The remaining two operands are usually lower and upper bounds
-     of the range.  But in some special cases they mean something else.  */
-  read_huge_number (pp, ';', &n2, &n2bits);
-  read_huge_number (pp, ';', &n3, &n3bits);
-
-  if (n2bits == -1 || n3bits == -1)
-    return error_type (pp);
-  
-  /* If limits are huge, must be large integral type.  */
-  if (n2bits != 0 || n3bits != 0)
-    {
-      char got_signed = 0;
-      char got_unsigned = 0;
-      /* Number of bits in the type.  */
-      int nbits;
-
-      /* Range from 0 to <large number> is an unsigned large integral type.  */
-      if ((n2bits == 0 && n2 == 0) && n3bits != 0)
-       {
-         got_unsigned = 1;
-         nbits = n3bits;
-       }
-      /* Range from <large number> to <large number>-1 is a large signed
-        integral type.  */
-      else if (n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1)
-       {
-         got_signed = 1;
-         nbits = n2bits;
-       }
-
-      /* Check for "long long".  */
-      if (got_signed && nbits == TARGET_LONG_LONG_BIT)
-       return builtin_type_long_long;
-      if (got_unsigned && nbits == TARGET_LONG_LONG_BIT)
-       return builtin_type_unsigned_long_long;
-
-      if (got_signed || got_unsigned)
-       {
-         result_type = (struct type *) obstack_alloc (symbol_obstack,
-                                                      sizeof (struct type));
-         bzero (result_type, sizeof (struct type));
-         TYPE_LENGTH (result_type) = nbits / TARGET_CHAR_BIT;
-         TYPE_MAIN_VARIANT (result_type) = result_type;
-         TYPE_CODE (result_type) = TYPE_CODE_INT;
-         if (got_unsigned)
-           TYPE_FLAGS (result_type) |= TYPE_FLAG_UNSIGNED;
-         return result_type;
-       }
-      else
-       return error_type (pp);
-    }
-
-  /* A type defined as a subrange of itself, with bounds both 0, is void.  */
-  if (self_subrange && n2 == 0 && n3 == 0)
-    return builtin_type_void;
-
-  /* If n3 is zero and n2 is not, we want a floating type,
-     and n2 is the width in bytes.
-
-     Fortran programs appear to use this for complex types also,
-     and they give no way to distinguish between double and single-complex!
-     We don't have complex types, so we would lose on all fortran files!
-     So return type `double' for all of those.  It won't work right
-     for the complex values, but at least it makes the file loadable.  */
-
-  if (n3 == 0 && n2 > 0)
-    {
-      if (n2 == sizeof (float))
-       return builtin_type_float;
-      return builtin_type_double;
-    }
-
-  /* If the upper bound is -1, it must really be an unsigned int.  */
-
-  else if (n2 == 0 && n3 == -1)
-    {
-      if (sizeof (int) == sizeof (long))
-       return builtin_type_unsigned_int;
-      else
-       return builtin_type_unsigned_long;
-    }
-
-  /* Special case: char is defined (Who knows why) as a subrange of
-     itself with range 0-127.  */
-  else if (self_subrange && n2 == 0 && n3 == 127)
-    return builtin_type_char;
-
-  /* Assumptions made here: Subrange of self is equivalent to subrange
-     of int.  */
-  else if (n2 == 0
-          && (self_subrange ||
-              *dbx_lookup_type (rangenums) == builtin_type_int))
-    {
-      /* an unsigned type */
-#ifdef LONG_LONG
-      if (n3 == - sizeof (long long))
-       return builtin_type_unsigned_long_long;
-#endif
-      if (n3 == (unsigned int)~0L)
-       return builtin_type_unsigned_int;
-      if (n3 == (unsigned long)~0L)
-       return builtin_type_unsigned_long;
-      if (n3 == (unsigned short)~0L)
-       return builtin_type_unsigned_short;
-      if (n3 == (unsigned char)~0L)
-       return builtin_type_unsigned_char;
-    }
-#ifdef LONG_LONG
-  else if (n3 == 0 && n2 == -sizeof (long long))
-    return builtin_type_long_long;
-#endif  
-  else if (n2 == -n3 -1)
-    {
-      /* a signed type */
-      if (n3 == (1 << (8 * sizeof (int) - 1)) - 1)
-       return builtin_type_int;
-      if (n3 == (1 << (8 * sizeof (long) - 1)) - 1)
-        return builtin_type_long;
-      if (n3 == (1 << (8 * sizeof (short) - 1)) - 1)
-       return builtin_type_short;
-      if (n3 == (1 << (8 * sizeof (char) - 1)) - 1)
-       return builtin_type_char;
-    }
-
-  /* We have a real range type on our hands.  Allocate space and
-     return a real pointer.  */
-
-  /* At this point I don't have the faintest idea how to deal with
-     a self_subrange type; I'm going to assume that this is used
-     as an idiom, and that all of them are special cases.  So . . .  */
-  if (self_subrange)
-    return error_type (pp);
-
-  result_type = (struct type *) obstack_alloc (symbol_obstack,
-                                              sizeof (struct type));
-  bzero (result_type, sizeof (struct type));
-
-  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, rangenums[1]);
-    TYPE_TARGET_TYPE (result_type) = builtin_type_int;
-  }
-
-  TYPE_NFIELDS (result_type) = 2;
-  TYPE_FIELDS (result_type) =
-     (struct field *) obstack_alloc (symbol_obstack,
-                                    2 * sizeof (struct field));
-  bzero (TYPE_FIELDS (result_type), 2 * sizeof (struct field));
-  TYPE_FIELD_BITPOS (result_type, 0) = n2;
-  TYPE_FIELD_BITPOS (result_type, 1) = n3;
-
-#if 0
-/* Note that TYPE_LENGTH (result_type) is just overridden a few
-   statements down.  What do we really need here?  */
-  /* We have to figure out how many bytes it takes to hold this
-     range type.  I'm going to assume that anything that is pushing
-     the bounds of a long was taken care of above.  */
-  if (n2 >= MIN_OF_C_TYPE(char) && n3 <= MAX_OF_C_TYPE(char))
-    TYPE_LENGTH (result_type) = 1;
-  else if (n2 >= MIN_OF_C_TYPE(short) && n3 <= MAX_OF_C_TYPE(short))
-    TYPE_LENGTH (result_type) = sizeof (short);
-  else if (n2 >= MIN_OF_C_TYPE(int) && n3 <= MAX_OF_C_TYPE(int))
-    TYPE_LENGTH (result_type) = sizeof (int);
-  else if (n2 >= MIN_OF_C_TYPE(long) && n3 <= MAX_OF_C_TYPE(long))
-    TYPE_LENGTH (result_type) = sizeof (long);
-  else
-    /* Ranged type doesn't fit within known sizes.  */
-    /* FIXME -- use "long long" here.  */
-    return error_type (pp);
-#endif
-
-  TYPE_LENGTH (result_type) = TYPE_LENGTH (TYPE_TARGET_TYPE (result_type));
-
-  return result_type;
-}
-
-/* Read a number from the string pointed to by *PP.
-   The value of *PP is advanced over the number.
-   If END is nonzero, the character that ends the
-   number must match END, or an error happens;
-   and that character is skipped if it does match.
-   If END is zero, *PP is left pointing to that character.  */
-
-static long
-read_number (pp, end)
-     char **pp;
-     int end;
-{
-  register char *p = *pp;
-  register long n = 0;
-  register int c;
-  int sign = 1;
-
-  /* Handle an optional leading minus sign.  */
-
-  if (*p == '-')
-    {
-      sign = -1;
-      p++;
-    }
-
-  /* Read the digits, as far as they go.  */
-
-  while ((c = *p++) >= '0' && c <= '9')
-    {
-      n *= 10;
-      n += c - '0';
-    }
-  if (end)
-    {
-      if (c && c != end)
-       error ("Invalid symbol data: invalid character \\%03o at symbol pos %d.", c, symnum);
-    }
-  else
-    --p;
-
-  *pp = p;
-  return n * sign;
-}
-
-/* Read in an argument list.  This is a list of types, separated by commas
-   and terminated with END.  Return the list of types read in, or (struct type
-   **)-1 if there is an error.  */
-static struct type **
-read_args (pp, end)
-     char **pp;
-     int end;
-{
-  struct type *types[1024], **rval; /* allow for fns of 1023 parameters */
-  int n = 0;
-
-  while (**pp != end)
-    {
-      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 ();
-
-      types[n++] = read_type (pp);
-    }
-  *pp += 1;                    /* get past `end' (the ':' character) */
-
-  if (n == 1)
-    {
-      rval = (struct type **) xmalloc (2 * sizeof (struct type *));
-    }
-  else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID)
-    {
-      rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *));
-      bzero (rval + n, sizeof (struct type *));
-    }
-  else
-    {
-      rval = (struct type **) xmalloc (n * sizeof (struct type *));
-    }
-  bcopy (types, rval, n * sizeof (struct type *));
-  return rval;
-}
 \f
 /* Copy a pending list, used to record the contents of a common
    block for later fixup.  */
@@ -5432,24 +2887,6 @@ copy_pending (beg, begi, end)
     }
   return new;
 }
-
-/* Add a common block's start address to the offset of each symbol
-   declared to be in it (by being between a BCOMM/ECOMM pair that uses
-   the common block name).  */
-
-static void
-fix_common_block (sym, valu)
-    struct symbol *sym;
-    int valu;
-{
-  struct pending *next = (struct pending *) SYMBOL_NAMESPACE (sym);
-  for ( ; next; next = next->next)
-    {
-      register int j;
-      for (j = next->nsyms - 1; j >= 0; j--)
-       SYMBOL_VALUE_ADDRESS (next->symbol[j]) += valu;
-    }
-}
 \f
 /* Register our willingness to decode symbols for SunOS and a.out and
    b.out files handled by BFD... */
@@ -5468,9 +2905,4 @@ _initialize_dbxread ()
   add_symtab_fns(&sunos_sym_fns);
   add_symtab_fns(&aout_sym_fns);
   add_symtab_fns(&bout_sym_fns);
-
-  undef_types_allocated = 20;
-  undef_types_length = 0;
-  undef_types = (struct type **) xmalloc (undef_types_allocated *
-                                         sizeof (struct type *));
 }