]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/dwarfread.c
This commit was generated by cvs2svn to track changes on a CVS vendor
[thirdparty/binutils-gdb.git] / gdb / dwarfread.c
index 2e522956866ffc560b92c7153ef7cfbefb34deca..9de03123d7d1e0660ef4c52dfeed6201cf806a9d 100644 (file)
@@ -1,5 +1,6 @@
 /* DWARF debugging format support for GDB.
-   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1998
+   Free Software Foundation, Inc.
    Written by Fred Fish at Cygnus Support.  Portions based on dbxread.c,
    mipsread.c, coffread.c, and dwarfread.c from a Data General SVR4 gdb port.
 
@@ -17,14 +18,12 @@ 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.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /*
 
-FIXME: Figure out how to get the frame pointer register number in the
-execution environment of the target.  Remove R_FP kludge
-
-FIXME: Add generation of dependencies list to partial symtab code.
+FIXME: Do we need to generate dependencies in partial symtabs?
+(Perhaps we don't need to).
 
 FIXME: Resolve minor differences between what information we put in the
 partial symbol table and what dbxread puts in.  For example, we don't yet
@@ -41,28 +40,136 @@ other things to work on, if you get bored. :-)
 */
 
 #include "defs.h"
-#include <varargs.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include "bfd.h"
 #include "symtab.h"
 #include "gdbtypes.h"
 #include "symfile.h"
 #include "objfiles.h"
-#include "libbfd.h"    /* FIXME Secret Internal BFD stuff (bfd_read) */
 #include "elf/dwarf.h"
 #include "buildsym.h"
+#include "demangle.h"
+#include "expression.h"        /* Needed for enum exp_opcode in language.h, sigh... */
+#include "language.h"
+#include "complaints.h"
 
-#ifdef MAINTENANCE     /* Define to 1 to compile in some maintenance stuff */
-#define SQUAWK(stuff) dwarfwarn stuff
-#else
-#define SQUAWK(stuff)
-#endif
+#include <fcntl.h>
+#include "gdb_string.h"
 
-#ifndef R_FP           /* FIXME */
-#define R_FP 14                /* Kludge to get frame pointer register number */
-#endif
+/* Some macros to provide DIE info for complaints. */
+
+#define DIE_ID (curdie!=NULL ? curdie->die_ref : 0)
+#define DIE_NAME (curdie!=NULL && curdie->at_name!=NULL) ? curdie->at_name : ""
+
+/* Complaints that can be issued during DWARF debug info reading. */
+
+struct complaint no_bfd_get_N =
+{
+  "DIE @ 0x%x \"%s\", no bfd support for %d byte data object", 0, 0
+};
+
+struct complaint malformed_die =
+{
+  "DIE @ 0x%x \"%s\", malformed DIE, bad length (%d bytes)", 0, 0
+};
+
+struct complaint bad_die_ref =
+{
+  "DIE @ 0x%x \"%s\", reference to DIE (0x%x) outside compilation unit", 0, 0
+};
+
+struct complaint unknown_attribute_form =
+{
+  "DIE @ 0x%x \"%s\", unknown attribute form (0x%x)", 0, 0
+};
+
+struct complaint unknown_attribute_length =
+{
+  "DIE @ 0x%x \"%s\", unknown attribute length, skipped remaining attributes", 0, 0
+};
+
+struct complaint unexpected_fund_type =
+{
+  "DIE @ 0x%x \"%s\", unexpected fundamental type 0x%x", 0, 0
+};
+
+struct complaint unknown_type_modifier =
+{
+  "DIE @ 0x%x \"%s\", unknown type modifier %u", 0, 0
+};
+
+struct complaint volatile_ignored =
+{
+  "DIE @ 0x%x \"%s\", type modifier 'volatile' ignored", 0, 0
+};
+
+struct complaint const_ignored =
+{
+  "DIE @ 0x%x \"%s\", type modifier 'const' ignored", 0, 0
+};
+
+struct complaint botched_modified_type =
+{
+  "DIE @ 0x%x \"%s\", botched modified type decoding (mtype 0x%x)", 0, 0
+};
+
+struct complaint op_deref2 =
+{
+  "DIE @ 0x%x \"%s\", OP_DEREF2 address 0x%x not handled", 0, 0
+};
+
+struct complaint op_deref4 =
+{
+  "DIE @ 0x%x \"%s\", OP_DEREF4 address 0x%x not handled", 0, 0
+};
+
+struct complaint basereg_not_handled =
+{
+  "DIE @ 0x%x \"%s\", BASEREG %d not handled", 0, 0
+};
+
+struct complaint dup_user_type_allocation =
+{
+  "DIE @ 0x%x \"%s\", internal error: duplicate user type allocation", 0, 0
+};
+
+struct complaint dup_user_type_definition =
+{
+  "DIE @ 0x%x \"%s\", internal error: duplicate user type definition", 0, 0
+};
+
+struct complaint missing_tag =
+{
+  "DIE @ 0x%x \"%s\", missing class, structure, or union tag", 0, 0
+};
+
+struct complaint bad_array_element_type =
+{
+  "DIE @ 0x%x \"%s\", bad array element type attribute 0x%x", 0, 0
+};
+
+struct complaint subscript_data_items =
+{
+  "DIE @ 0x%x \"%s\", can't decode subscript data items", 0, 0
+};
+
+struct complaint unhandled_array_subscript_format =
+{
+  "DIE @ 0x%x \"%s\", array subscript format 0x%x not handled yet", 0, 0
+};
+
+struct complaint unknown_array_subscript_format =
+{
+  "DIE @ 0x%x \"%s\", unknown array subscript format %x", 0, 0
+};
+
+struct complaint not_row_major =
+{
+  "DIE @ 0x%x \"%s\", array not row major; not handled correctly", 0, 0
+};
+
+struct complaint missing_at_name =
+{
+  "DIE @ 0x%x, AT_name tag missing", 0, 0
+};
 
 typedef unsigned int DIE_REF;  /* Reference to a DIE */
 
@@ -70,8 +177,22 @@ typedef unsigned int DIE_REF;       /* Reference to a DIE */
 #define GCC_PRODUCER "GNU C "
 #endif
 
-#define STREQ(a,b)             (strcmp(a,b)==0)
-#define STREQN(a,b,n)          (strncmp(a,b,n)==0)
+#ifndef GPLUS_PRODUCER
+#define GPLUS_PRODUCER "GNU C++ "
+#endif
+
+#ifndef LCC_PRODUCER
+#define LCC_PRODUCER "NCR C/C++"
+#endif
+
+#ifndef CHILL_PRODUCER
+#define CHILL_PRODUCER "GNU Chill "
+#endif
+
+/* Provide a default mapping from a DWARF register number to a gdb REGNUM.  */
+#ifndef DWARF_REG_TO_REGNUM
+#define DWARF_REG_TO_REGNUM(num) (num)
+#endif
 
 /* Flags to target_to_host() that tell whether or not the data object is
    expected to be signed.  Used, for example, when fetching a signed
@@ -176,69 +297,82 @@ struct dieinfo {
   unsigned long                at_bit_size;
   BLOCK *              at_element_list;
   unsigned long                at_stmt_list;
-  unsigned long                at_low_pc;
-  unsigned long                at_high_pc;
+  CORE_ADDR            at_low_pc;
+  CORE_ADDR            at_high_pc;
   unsigned long                at_language;
   unsigned long                at_member;
   unsigned long                at_discr;
   BLOCK *              at_discr_value;
-  unsigned short       at_visibility;
-  unsigned long                at_import;
   BLOCK *              at_string_length;
   char *               at_comp_dir;
   char *               at_producer;
-  unsigned long                at_frame_base;
   unsigned long                at_start_scope;
   unsigned long                at_stride_size;
   unsigned long                at_src_info;
   char *               at_prototyped;
   unsigned int         has_at_low_pc:1;
   unsigned int         has_at_stmt_list:1;
+  unsigned int         has_at_byte_size:1;
   unsigned int         short_element_list:1;
+
+  /* Kludge to identify register variables */
+
+  unsigned int         isreg;
+
+  /* Kludge to identify optimized out variables */
+
+  unsigned int         optimized_out;
+
+  /* Kludge to identify basereg references.
+     Nonzero if we have an offset relative to a basereg.  */
+
+  unsigned int         offreg;
+
+  /* Kludge to identify which base register is it relative to.  */
+
+  unsigned int         basereg;
 };
 
 static int diecount;   /* Approximate count of dies for compilation unit */
 static struct dieinfo *curdie; /* For warnings and such */
 
 static char *dbbase;   /* Base pointer to dwarf info */
+static int dbsize;     /* Size of dwarf info in bytes */
 static int dbroff;     /* Relative offset from start of .debug section */
 static char *lnbase;   /* Base pointer to line section */
-static int isreg;      /* Kludge to identify register variables */
-static int offreg;     /* Kludge to identify basereg references */
 
+/* This value is added to each symbol value.  FIXME:  Generalize to 
+   the section_offsets structure used by dbxread (once this is done,
+   pass the appropriate section number to end_symtab).  */
 static CORE_ADDR baseaddr;     /* Add to each symbol value */
 
-/* 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.  For DWARF debugging info, this data is
-   contained in the following structure and macros are provided for easy
-   access to the members given a pointer to a partial symbol table entry.
-
-   dbfoff      Always the absolute file offset to the start of the ".debug"
-               section for the file containing the DIE's being accessed.
-
-   dbroff      Relative offset from the start of the ".debug" access to the
-               first DIE to be accessed.  When building the partial symbol
-               table, this value will be zero since we are accessing the
-               entire ".debug" section.  When expanding a partial symbol
-               table entry, this value will be the offset to the first
-               DIE for the compilation unit containing the symbol that
-               triggers the expansion.
-
-   dblength    The size of the chunk of DIE's being examined, in bytes.
-
-   lnfoff      The absolute file offset to the line table fragment.  Ignored
-               when building partial symbol tables, but used when expanding
-               them, and contains the absolute file offset to the fragment
-               of the ".line" section containing the line numbers for the
-               current compilation unit.
- */
+/* The section offsets used in the current psymtab or symtab.  FIXME,
+   only used to pass one value (baseaddr) at the moment.  */
+static struct section_offsets *base_section_offsets;
+
+/* We put a pointer to this structure in the read_symtab_private field
+   of the psymtab.  */
 
 struct dwfinfo {
-  int dbfoff;          /* Absolute file offset to start of .debug section */
-  int dbroff;          /* Relative offset from start of .debug section */
-  int dblength;                /* Size of the chunk of DIE's being examined */
-  int lnfoff;          /* Absolute file offset to line table fragment */
+  /* Always the absolute file offset to the start of the ".debug"
+     section for the file containing the DIE's being accessed.  */
+  file_ptr dbfoff;
+  /* Relative offset from the start of the ".debug" section to the
+     first DIE to be accessed.  When building the partial symbol
+     table, this value will be zero since we are accessing the
+     entire ".debug" section.  When expanding a partial symbol
+     table entry, this value will be the offset to the first
+     DIE for the compilation unit containing the symbol that
+     triggers the expansion.  */
+  int dbroff;
+  /* The size of the chunk of DIE's being examined, in bytes.  */
+  int dblength;
+  /* The absolute file offset to the line table fragment.  Ignored
+     when building partial symbol tables, but used when expanding
+     them, and contains the absolute file offset to the fragment
+     of the ".line" section containing the line numbers for the
+     current compilation unit.  */
+  file_ptr lnfoff;
 };
 
 #define DBFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbfoff)
@@ -278,23 +412,57 @@ struct pending **list_in_scope = &file_symbols;
    we can divide any DIE offset by 4 to obtain a unique index into this fixed
    size array.  Since each element is a 4 byte pointer, it takes exactly as
    much memory to hold this array as to hold the DWARF info for a given
-   compilation unit.  But it gets freed as soon as we are done with it. */
+   compilation unit.  But it gets freed as soon as we are done with it.
+   This has worked well in practice, as a reasonable tradeoff between memory
+   consumption and speed, without having to resort to much more complicated
+   algorithms. */
 
 static struct type **utypes;   /* Pointer to array of user type pointers */
 static int numutypes;          /* Max number of user type pointers */
 
+/* Maintain an array of referenced fundamental types for the current
+   compilation unit being read.  For DWARF version 1, we have to construct
+   the fundamental types on the fly, since no information about the
+   fundamental types is supplied.  Each such fundamental type is created by
+   calling a language dependent routine to create the type, and then a
+   pointer to that type is then placed in the array at the index specified
+   by it's FT_<TYPENAME> value.  The array has a fixed size set by the
+   FT_NUM_MEMBERS compile time constant, which is the number of predefined
+   fundamental types gdb knows how to construct. */
+
+static struct type *ftypes[FT_NUM_MEMBERS];  /* Fundamental types */
+
+/* Record the language for the compilation unit which is currently being
+   processed.  We know it once we have seen the TAG_compile_unit DIE,
+   and we need it while processing the DIE's for that compilation unit.
+   It is eventually saved in the symtab structure, but we don't finalize
+   the symtab struct until we have processed all the DIE's for the
+   compilation unit.  We also need to get and save a pointer to the 
+   language struct for this language, so we can call the language
+   dependent routines for doing things such as creating fundamental
+   types. */
+
+static enum language cu_language;
+static const struct language_defn *cu_language_defn;
+
 /* Forward declarations of static functions so we don't have to worry
    about ordering within this file.  */
 
+static void
+free_utypes PARAMS ((PTR));
+
 static int
 attribute_size PARAMS ((unsigned int));
 
-static unsigned long
+static CORE_ADDR
 target_to_host PARAMS ((char *, int, int, struct objfile *));
 
 static void
 add_enum_psymbol PARAMS ((struct dieinfo *, struct objfile *));
 
+static void
+handle_producer PARAMS ((char *));
+
 static void
 read_file_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
 
@@ -305,22 +473,16 @@ static void
 read_lexical_block_scope PARAMS ((struct dieinfo *, char *, char *,
                                  struct objfile *));
 
-static void
-dwarfwarn ();
-
 static void
 scan_partial_symbols PARAMS ((char *, char *, struct objfile *));
 
 static void
-scan_compilation_units PARAMS ((char *, char *, char *, unsigned int,
-                               unsigned int, struct objfile *));
+scan_compilation_units PARAMS ((char *, char *, file_ptr,
+                               file_ptr, struct objfile *));
 
 static void
 add_partial_symbol PARAMS ((struct dieinfo *, struct objfile *));
 
-static void
-init_psymbol_list PARAMS ((struct objfile *, int));
-
 static void
 basicdieinfo PARAMS ((struct dieinfo *, char *, struct objfile *));
 
@@ -333,7 +495,7 @@ dwarf_psymtab_to_symtab PARAMS ((struct partial_symtab *));
 static void
 psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
 
-static struct symtab *
+static void
 read_ofile_symtab PARAMS ((struct partial_symtab *));
 
 static void
@@ -347,7 +509,7 @@ static struct type *
 decode_array_element_type PARAMS ((char *));
 
 static struct type *
-decode_subscr_data PARAMS ((char *, char *));
+decode_subscript_data_item PARAMS ((char *, char *));
 
 static void
 dwarf_read_array_type PARAMS ((struct dieinfo *));
@@ -355,6 +517,9 @@ dwarf_read_array_type PARAMS ((struct dieinfo *));
 static void
 read_tag_pointer_type PARAMS ((struct dieinfo *dip));
 
+static void
+read_tag_string_type PARAMS ((struct dieinfo *dip));
+
 static void
 read_subroutine_type PARAMS ((struct dieinfo *, char *, char *));
 
@@ -380,7 +545,7 @@ static struct type *
 decode_mod_u_d_type PARAMS ((char *));
 
 static struct type *
-decode_modified_type PARAMS ((unsigned char *, unsigned int, int));
+decode_modified_type PARAMS ((char *, unsigned int, int));
 
 static struct type *
 decode_fund_type PARAMS ((unsigned int));
@@ -397,12 +562,136 @@ alloc_utype PARAMS ((DIE_REF, struct type *));
 static struct symbol *
 new_symbol PARAMS ((struct dieinfo *, struct objfile *));
 
+static void
+synthesize_typedef PARAMS ((struct dieinfo *, struct objfile *,
+                           struct type *));
+
 static int
-locval PARAMS ((char *));
+locval PARAMS ((struct dieinfo *));
+
+static void
+set_cu_language PARAMS ((struct dieinfo *));
+
+static struct type *
+dwarf_fundamental_type PARAMS ((struct objfile *, int));
+
+
+/*
+
+LOCAL FUNCTION
+
+       dwarf_fundamental_type -- lookup or create a fundamental type
+
+SYNOPSIS
+
+       struct type *
+       dwarf_fundamental_type (struct objfile *objfile, int typeid)
+
+DESCRIPTION
+
+       DWARF version 1 doesn't supply any fundamental type information,
+       so gdb has to construct such types.  It has a fixed number of
+       fundamental types that it knows how to construct, which is the
+       union of all types that it knows how to construct for all languages
+       that it knows about.  These are enumerated in gdbtypes.h.
+
+       As an example, assume we find a DIE that references a DWARF
+       fundamental type of FT_integer.  We first look in the ftypes
+       array to see if we already have such a type, indexed by the
+       gdb internal value of FT_INTEGER.  If so, we simply return a
+       pointer to that type.  If not, then we ask an appropriate
+       language dependent routine to create a type FT_INTEGER, using
+       defaults reasonable for the current target machine, and install
+       that type in ftypes for future reference.
+
+RETURNS
+
+       Pointer to a fundamental type.
+
+*/
+
+static struct type *
+dwarf_fundamental_type (objfile, typeid)
+     struct objfile *objfile;
+     int typeid;
+{
+  if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
+    {
+      error ("internal error - invalid fundamental type id %d", typeid);
+    }
+
+  /* Look for this particular type in the fundamental type vector.  If one is
+     not found, create and install one appropriate for the current language
+     and the current target machine. */
+
+  if (ftypes[typeid] == NULL)
+    {
+      ftypes[typeid] = cu_language_defn -> la_fund_type(objfile, typeid);
+    }
+
+  return (ftypes[typeid]);
+}
+
+/*
+
+LOCAL FUNCTION
+
+       set_cu_language -- set local copy of language for compilation unit
+
+SYNOPSIS
+
+       void
+       set_cu_language (struct dieinfo *dip)
+
+DESCRIPTION
+
+       Decode the language attribute for a compilation unit DIE and
+       remember what the language was.  We use this at various times
+       when processing DIE's for a given compilation unit.
+
+RETURNS
+
+       No return value.
+
+ */
 
 static void
-record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type,
-                              struct objfile *));
+set_cu_language (dip)
+     struct dieinfo *dip;
+{
+  switch (dip -> at_language)
+    {
+      case LANG_C89:
+      case LANG_C:
+        cu_language = language_c;
+       break;
+      case LANG_C_PLUS_PLUS:
+       cu_language = language_cplus;
+       break;
+      case LANG_CHILL:
+       cu_language = language_chill;
+       break;
+      case LANG_MODULA2:
+       cu_language = language_m2;
+       break;
+      case LANG_FORTRAN77:
+      case LANG_FORTRAN90:
+       cu_language = language_fortran;
+       break;
+      case LANG_ADA83:
+      case LANG_COBOL74:
+      case LANG_COBOL85:
+      case LANG_PASCAL83:
+       /* We don't know anything special about these yet. */
+       cu_language = language_unknown;
+       break;
+      default:
+       /* If no at_language, try to deduce one from the filename */
+       cu_language = deduce_language_from_filename (dip -> at_name);
+       break;
+    }
+  cu_language_defn = language_def (cu_language);
+}
 
 /*
 
@@ -412,17 +701,17 @@ GLOBAL FUNCTION
 
 SYNOPSIS
 
-       void dwarf_build_psymtabs (int desc, char *filename, CORE_ADDR addr,
-            int mainline, unsigned int dbfoff, unsigned int dbsize,
-            unsigned int lnoffset, unsigned int lnsize,
-            struct objfile *objfile)
+       void dwarf_build_psymtabs (struct objfile *objfile,
+            struct section_offsets *section_offsets,
+            int mainline, file_ptr dbfoff, unsigned int dbfsize,
+            file_ptr lnoffset, unsigned int lnsize)
 
 DESCRIPTION
 
        This function is called upon to build partial symtabs from files
        containing DIE's (Dwarf Information Entries) and DWARF line numbers.
 
-       It is passed a file descriptor for an open file containing the DIES
+       It is passed a bfd* containing the DIES
        and line number information, the corresponding filename for that
        file, a base address for relocating the symbols, a flag indicating
        whether or not this debugging information is from a "main symbol
@@ -437,28 +726,28 @@ RETURNS
  */
 
 void
-dwarf_build_psymtabs (desc, filename, addr, mainline, dbfoff, dbsize,
-                     lnoffset, lnsize, objfile)
-     int desc;
-     char *filename;
-     CORE_ADDR addr;
+dwarf_build_psymtabs (objfile, section_offsets, mainline, dbfoff, dbfsize,
+                     lnoffset, lnsize)
+     struct objfile *objfile;
+     struct section_offsets *section_offsets;
      int mainline;
-     unsigned int dbfoff;
-     unsigned int dbsize;
-     unsigned int lnoffset;
+     file_ptr dbfoff;
+     unsigned int dbfsize;
+     file_ptr lnoffset;
      unsigned int lnsize;
-     struct objfile *objfile;
 {
+  bfd *abfd = objfile->obfd;
   struct cleanup *back_to;
   
   current_objfile = objfile;
+  dbsize = dbfsize;
   dbbase = xmalloc (dbsize);
   dbroff = 0;
-  if ((lseek (desc, dbfoff, 0) != dbfoff) ||
-      (read (desc, dbbase, dbsize) != dbsize))
+  if ((bfd_seek (abfd, dbfoff, SEEK_SET) != 0) ||
+      (bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
     {
       free (dbbase);
-      error ("can't read DWARF data from '%s'", filename);
+      error ("can't read DWARF data from '%s'", bfd_get_filename (abfd));
     }
   back_to = make_cleanup (free, dbbase);
   
@@ -474,101 +763,19 @@ dwarf_build_psymtabs (desc, filename, addr, mainline, dbfoff, dbsize,
   
   /* Save the relocation factor where everybody can see it.  */
 
-  baseaddr = addr;
+  base_section_offsets = section_offsets;
+  baseaddr = ANOFFSET (section_offsets, 0);
 
   /* Follow the compilation unit sibling chain, building a partial symbol
      table entry for each one.  Save enough information about each compilation
      unit to locate the full DWARF information later. */
   
-  scan_compilation_units (filename, dbbase, dbbase + dbsize,
-                         dbfoff, lnoffset, objfile);
+  scan_compilation_units (dbbase, dbbase + dbsize, dbfoff, lnoffset, objfile);
   
   do_cleanups (back_to);
   current_objfile = NULL;
 }
 
-
-/*
-
-LOCAL FUNCTION
-
-       record_minimal_symbol -- add entry to gdb's minimal symbol table
-
-SYNOPSIS
-
-       static void record_minimal_symbol (char *name, CORE_ADDR address,
-                                         enum minimal_symbol_type ms_type,
-                                         struct objfile *objfile)
-
-DESCRIPTION
-
-       Given a pointer to the name of a symbol that should be added to the
-       minimal symbol table, and the address associated with that
-       symbol, records this information for later use in building the
-       minimal symbol table.
-
- */
-
-static void
-record_minimal_symbol (name, address, ms_type, objfile)
-     char *name;
-     CORE_ADDR address;
-     enum minimal_symbol_type ms_type;
-     struct objfile *objfile;
-{
-  name = obsavestring (name, strlen (name), &objfile -> symbol_obstack);
-  prim_record_minimal_symbol (name, address, ms_type);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       dwarfwarn -- issue a DWARF related warning
-
-DESCRIPTION
-
-       Issue warnings about DWARF related things that aren't serious enough
-       to warrant aborting with an error, but should not be ignored either.
-       This includes things like detectable corruption in DIE's, missing
-       DIE's, unimplemented features, etc.
-
-       In general, running across tags or attributes that we don't recognize
-       is not considered to be a problem and we should not issue warnings
-       about such.
-
-NOTES
-
-       We mostly follow the example of the error() routine, but without
-       returning to command level.  It is arguable about whether warnings
-       should be issued at all, and if so, where they should go (stdout or
-       stderr).
-
-       We assume that curdie is valid and contains at least the basic
-       information for the DIE where the problem was noticed.
-*/
-
-static void
-dwarfwarn (va_alist)
-     va_dcl
-{
-  va_list ap;
-  char *fmt;
-  
-  va_start (ap);
-  fmt = va_arg (ap, char *);
-  warning_setup ();
-  fprintf (stderr, "warning: DWARF ref 0x%x: ", curdie -> die_ref);
-  if (curdie -> at_name)
-    {
-      fprintf (stderr, "'%s': ", curdie -> at_name);
-    }
-  vfprintf (stderr, fmt, ap);
-  fprintf (stderr, "\n");
-  fflush (stderr);
-  va_end (ap);
-}
-
 /*
 
 LOCAL FUNCTION
@@ -596,7 +803,7 @@ read_lexical_block_scope (dip, thisdie, enddie, objfile)
 {
   register struct context_stack *new;
 
-  (void) push_context (0, dip -> at_low_pc);
+  push_context (0, dip -> at_low_pc);
   process_dies (thisdie + dip -> die_length, enddie, objfile);
   new = pop_context ();
   if (local_symbols != NULL)
@@ -636,7 +843,7 @@ lookup_utype (die_ref)
   utypeidx = (die_ref - dbroff) / 4;
   if ((utypeidx < 0) || (utypeidx >= numutypes))
     {
-      dwarfwarn ("reference to DIE (0x%x) outside compilation unit", die_ref);
+      complain (&bad_die_ref, DIE_ID, DIE_NAME);
     }
   else
     {
@@ -679,29 +886,52 @@ alloc_utype (die_ref, utypep)
   typep = utypes + utypeidx;
   if ((utypeidx < 0) || (utypeidx >= numutypes))
     {
-      utypep = lookup_fundamental_type (current_objfile, FT_INTEGER);
-      dwarfwarn ("reference to DIE (0x%x) outside compilation unit", die_ref);
+      utypep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+      complain (&bad_die_ref, DIE_ID, DIE_NAME);
     }
   else if (*typep != NULL)
     {
       utypep = *typep;
-      SQUAWK (("internal error: dup user type allocation"));
+      complain (&dup_user_type_allocation, DIE_ID, DIE_NAME);
     }
   else
     {
       if (utypep == NULL)
        {
-         utypep = (struct type *)
-           obstack_alloc (&current_objfile -> type_obstack,
-                          sizeof (struct type));
-         (void) memset (utypep, 0, sizeof (struct type));
-         TYPE_OBJFILE (utypep) = current_objfile;
+         utypep = alloc_type (current_objfile);
        }
       *typep = utypep;
     }
   return (utypep);
 }
 
+/*
+
+LOCAL FUNCTION
+
+       free_utypes -- free the utypes array and reset pointer & count
+
+SYNOPSIS
+
+       static void free_utypes (PTR dummy)
+
+DESCRIPTION
+
+       Called via do_cleanups to free the utypes array, reset the pointer to NULL,
+       and set numutypes back to zero.  This ensures that the utypes does not get
+       referenced after being freed.
+ */
+
+static void
+free_utypes (dummy)
+     PTR dummy;
+{
+  free (utypes);
+  utypes = NULL;
+  numutypes = 0;
+}
+
+
 /*
 
 LOCAL FUNCTION
@@ -746,7 +976,7 @@ decode_die_type (dip)
     }
   else
     {
-      type = lookup_fundamental_type (current_objfile, FT_INTEGER);
+      type = dwarf_fundamental_type (current_objfile, FT_VOID);
     }
   return (type);
 }
@@ -787,9 +1017,9 @@ struct_type (dip, thisdie, enddie, objfile)
   struct nextfield *new;
   int nfields = 0;
   int n;
-  char *tpart1;
   struct dieinfo mbr;
   char *nextdie;
+  int anonymous_size;
   
   if ((type = lookup_utype (dip -> die_ref)) == NULL)
     {
@@ -799,19 +1029,19 @@ struct_type (dip, thisdie, enddie, objfile)
   INIT_CPLUS_SPECIFIC(type);
   switch (dip -> die_tag)
     {
+      case TAG_class_type:
+        TYPE_CODE (type) = TYPE_CODE_CLASS;
+       break;
       case TAG_structure_type:
         TYPE_CODE (type) = TYPE_CODE_STRUCT;
-       tpart1 = "struct";
        break;
       case TAG_union_type:
        TYPE_CODE (type) = TYPE_CODE_UNION;
-       tpart1 = "union";
        break;
       default:
        /* Should never happen */
        TYPE_CODE (type) = TYPE_CODE_UNDEF;
-       tpart1 = "???";
-       SQUAWK (("missing structure or union tag"));
+       complain (&missing_tag, DIE_ID, DIE_NAME);
        break;
     }
   /* Some compilers try to be helpful by inventing "fake" names for
@@ -821,13 +1051,15 @@ struct_type (dip, thisdie, enddie, objfile)
       && *dip -> at_name != '~'
       && *dip -> at_name != '.')
     {
-      TYPE_NAME (type) = obconcat (&objfile -> type_obstack,
-                                  tpart1, " ", dip -> at_name);
-    }
-  if (dip -> at_byte_size != 0)
-    {
-      TYPE_LENGTH (type) = dip -> at_byte_size;
+      TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack,
+                                      "", "", dip -> at_name);
     }
+  /* Use whatever size is known.  Zero is a valid size.  We might however
+     wish to check has_at_byte_size to make sure that some byte size was
+     given explicitly, but DWARF doesn't specify that explicit sizes of
+     zero have to present, so complaining about missing sizes should 
+     probably not be the default. */
+  TYPE_LENGTH (type) = dip -> at_byte_size;
   thisdie += dip -> die_length;
   while (thisdie < enddie)
     {
@@ -853,10 +1085,54 @@ struct_type (dip, thisdie, enddie, objfile)
          new -> next = list;
          list = new;
          /* Save the data.  */
-         list -> field.name = savestring (mbr.at_name, strlen (mbr.at_name));
-         list -> field.type = decode_die_type (&mbr);
-         list -> field.bitpos = 8 * locval (mbr.at_location);
-         list -> field.bitsize = 0;
+         list -> field.name =
+             obsavestring (mbr.at_name, strlen (mbr.at_name),
+                           &objfile -> type_obstack);
+         FIELD_TYPE (list->field) = decode_die_type (&mbr);
+         FIELD_BITPOS (list->field) = 8 * locval (&mbr);
+         /* Handle bit fields. */
+         FIELD_BITSIZE (list->field) = mbr.at_bit_size;
+         if (BITS_BIG_ENDIAN)
+           {
+             /* For big endian bits, the at_bit_offset gives the
+                additional bit offset from the MSB of the containing
+                anonymous object to the MSB of the field.  We don't
+                have to do anything special since we don't need to
+                know the size of the anonymous object. */
+             FIELD_BITPOS (list->field) += mbr.at_bit_offset;
+           }
+         else
+           {
+             /* For little endian bits, we need to have a non-zero
+                at_bit_size, so that we know we are in fact dealing
+                with a bitfield.  Compute the bit offset to the MSB
+                of the anonymous object, subtract off the number of
+                bits from the MSB of the field to the MSB of the
+                object, and then subtract off the number of bits of
+                the field itself.  The result is the bit offset of
+                the LSB of the field. */
+             if (mbr.at_bit_size > 0)
+               {
+                 if (mbr.has_at_byte_size)
+                   {
+                     /* The size of the anonymous object containing
+                        the bit field is explicit, so use the
+                        indicated size (in bytes). */
+                     anonymous_size = mbr.at_byte_size;
+                   }
+                 else
+                   {
+                     /* The size of the anonymous object containing
+                        the bit field matches the size of an object
+                        of the bit field's type.  DWARF allows
+                        at_byte_size to be left out in such cases, as
+                        a debug information size optimization. */
+                     anonymous_size = TYPE_LENGTH (list -> field.type);
+                   }
+                 FIELD_BITPOS (list->field) +=
+                   anonymous_size * 8 - mbr.at_bit_offset - mbr.at_bit_size;
+               }
+           }
          nfields++;
          break;
        default:
@@ -878,8 +1154,7 @@ struct_type (dip, thisdie, enddie, objfile)
     {
       TYPE_NFIELDS (type) = nfields;
       TYPE_FIELDS (type) = (struct field *)
-       obstack_alloc (&objfile -> type_obstack,
-                      sizeof (struct field) * nfields);
+       TYPE_ALLOC (type, sizeof (struct field) * nfields);
       /* Copy the saved-up fields into the field vector.  */
       for (n = nfields; list; list = list -> next)
        {
@@ -936,9 +1211,14 @@ read_structure_scope (dip, thisdie, enddie, objfile)
   type = struct_type (dip, thisdie, enddie, objfile);
   if (!(TYPE_FLAGS (type) & TYPE_FLAG_STUB))
     {
-      if ((sym = new_symbol (dip, objfile)) != NULL)
+      sym = new_symbol (dip, objfile);
+      if (sym != NULL)
        {
          SYMBOL_TYPE (sym) = type;
+         if (cu_language == language_cplus)
+           {
+             synthesize_typedef (dip, objfile, type);
+           }
        }
     }
 }
@@ -977,8 +1257,8 @@ decode_array_element_type (scan)
   scan += SIZEOF_ATTRIBUTE;
   if ((nbytes = attribute_size (attribute)) == -1)
     {
-      SQUAWK (("bad array element type attribute 0x%x", attribute));
-      typep = lookup_fundamental_type (current_objfile, FT_INTEGER);
+      complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute);
+      typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
     }
   else
     {
@@ -1004,8 +1284,8 @@ decode_array_element_type (scan)
            typep = decode_mod_u_d_type (scan);
            break;
          default:
-           SQUAWK (("bad array element type attribute 0x%x", attribute));
-           typep = lookup_fundamental_type (current_objfile, FT_INTEGER);
+           complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute);
+           typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
            break;
          }
     }
@@ -1016,11 +1296,12 @@ decode_array_element_type (scan)
 
 LOCAL FUNCTION
 
-       decode_subscr_data -- decode array subscript and element type data
+       decode_subscript_data_item -- decode array subscript item
 
 SYNOPSIS
 
-       static struct type *decode_subscr_data (char *scan, char *end)
+       static struct type *
+       decode_subscript_data_item (char *scan, char *end)
 
 DESCRIPTION
 
@@ -1032,9 +1313,21 @@ DESCRIPTION
        source (I.E. leftmost dimension first, next to leftmost second,
        etc).
 
+       The data items describing each array dimension consist of four
+       parts: (1) a format specifier, (2) type type of the subscript
+       index, (3) a description of the low bound of the array dimension,
+       and (4) a description of the high bound of the array dimension.
+
+       The last data item is the description of the type of each of
+       the array elements.
+
        We are passed a pointer to the start of the block of bytes
-       containing the data items, and a pointer to the first byte past
-       the data.  This function decodes the data and returns a type.
+       containing the remaining data items, and a pointer to the first
+       byte past the data.  This function recursively decodes the
+       remaining data items and returns a type.
+
+       If we somehow fail to decode some data, we complain about it
+       and return a type "array of int".
 
 BUGS
        FIXME:  This code only implements the forms currently used
@@ -1045,12 +1338,14 @@ BUGS
  */
 
 static struct type *
-decode_subscr_data (scan, end)
+decode_subscript_data_item (scan, end)
      char *scan;
      char *end;
 {
-  struct type *typep = NULL;
-  struct type *nexttype;
+  struct type *typep = NULL;   /* Array type we are building */
+  struct type *nexttype;       /* Type of each element (may be array) */
+  struct type *indextype;      /* Type of this index */
+  struct type *rangetype;
   unsigned int format;
   unsigned short fundtype;
   unsigned long lowbound;
@@ -1068,36 +1363,23 @@ decode_subscr_data (scan, end)
     case FMT_FT_C_C:
       fundtype = target_to_host (scan, SIZEOF_FMT_FT, GET_UNSIGNED,
                                 current_objfile);
+      indextype = decode_fund_type (fundtype);
       scan += SIZEOF_FMT_FT;
-      if (fundtype != FT_integer && fundtype != FT_signed_integer
-         && fundtype != FT_unsigned_integer)
+      nbytes = TARGET_FT_LONG_SIZE (current_objfile);
+      lowbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile);
+      scan += nbytes;
+      highbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile);
+      scan += nbytes;
+      nexttype = decode_subscript_data_item (scan, end);
+      if (nexttype == NULL)
        {
-         SQUAWK (("array subscripts must be integral types, not type 0x%x",
-                  fundtype));
-       }
-      else
-       {
-         nbytes = TARGET_FT_LONG_SIZE (current_objfile);
-         lowbound = target_to_host (scan, nbytes, GET_UNSIGNED,
-                                    current_objfile);
-         scan += nbytes;
-         highbound = target_to_host (scan, nbytes, GET_UNSIGNED,
-                                     current_objfile);
-         scan += nbytes;
-         nexttype = decode_subscr_data (scan, end);
-         if (nexttype != NULL)
-           {
-             typep = (struct type *)
-               obstack_alloc (&current_objfile -> type_obstack,
-                              sizeof (struct type));
-             (void) memset (typep, 0, sizeof (struct type));
-             TYPE_OBJFILE (typep) = current_objfile;
-             TYPE_CODE (typep) = TYPE_CODE_ARRAY;
-             TYPE_LENGTH (typep) = TYPE_LENGTH (nexttype);
-             TYPE_LENGTH (typep) *= lowbound + highbound + 1;
-             TYPE_TARGET_TYPE (typep) = nexttype;
-           }               
+         /* Munged subscript data or other problem, fake it. */
+         complain (&subscript_data_items, DIE_ID, DIE_NAME);
+         nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
        }
+      rangetype = create_range_type ((struct type *) NULL, indextype,
+                                     lowbound, highbound);
+      typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
       break;
     case FMT_FT_C_X:
     case FMT_FT_X_C:
@@ -1106,10 +1388,16 @@ decode_subscr_data (scan, end)
     case FMT_UT_C_X:
     case FMT_UT_X_C:
     case FMT_UT_X_X:
-      SQUAWK (("array subscript format 0x%x not handled yet", format));
+      complain (&unhandled_array_subscript_format, DIE_ID, DIE_NAME, format);
+      nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+      rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0);
+      typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
       break;
     default:
-      SQUAWK (("unknown array subscript format %x", format));
+      complain (&unknown_array_subscript_format, DIE_ID, DIE_NAME, format);
+      nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+      rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0);
+      typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
       break;
     }
   return (typep);
@@ -1145,7 +1433,7 @@ dwarf_read_array_type (dip)
   if (dip -> at_ordering != ORD_row_major)
     {
       /* FIXME:  Can gdb even handle column major arrays? */
-      SQUAWK (("array not row major; not handled correctly"));
+      complain (&not_row_major, DIE_ID, DIE_NAME);
     }
   if ((sub = dip -> at_subscr_data) != NULL)
     {
@@ -1153,30 +1441,29 @@ dwarf_read_array_type (dip)
       blocksz = target_to_host (sub, nbytes, GET_UNSIGNED, current_objfile);
       subend = sub + nbytes + blocksz;
       sub += nbytes;
-      type = decode_subscr_data (sub, subend);
-      if (type == NULL)
+      type = decode_subscript_data_item (sub, subend);
+      if ((utype = lookup_utype (dip -> die_ref)) == NULL)
        {
-         if ((utype = lookup_utype (dip -> die_ref)) == NULL)
-           {
-             utype = alloc_utype (dip -> die_ref, NULL);
-           }
-         TYPE_CODE (utype) = TYPE_CODE_ARRAY;
-         TYPE_TARGET_TYPE (utype) = 
-           lookup_fundamental_type (current_objfile, FT_INTEGER);
-         TYPE_LENGTH (utype) = 1 * TYPE_LENGTH (TYPE_TARGET_TYPE (utype));
+         /* Install user defined type that has not been referenced yet. */
+         alloc_utype (dip -> die_ref, type);
+       }
+      else if (TYPE_CODE (utype) == TYPE_CODE_UNDEF)
+       {
+         /* Ick!  A forward ref has already generated a blank type in our
+            slot, and this type probably already has things pointing to it
+            (which is what caused it to be created in the first place).
+            If it's just a place holder we can plop our fully defined type
+            on top of it.  We can't recover the space allocated for our
+            new type since it might be on an obstack, but we could reuse
+            it if we kept a list of them, but it might not be worth it
+            (FIXME). */
+         *utype = *type;
        }
       else
        {
-         if ((utype = lookup_utype (dip -> die_ref)) == NULL)
-           {
-             (void) alloc_utype (dip -> die_ref, type);
-           }
-         else
-           {
-             TYPE_CODE (utype) = TYPE_CODE_ARRAY;
-             TYPE_LENGTH (utype) = TYPE_LENGTH (type);
-             TYPE_TARGET_TYPE (utype) = TYPE_TARGET_TYPE (type);
-           }
+         /* Double ick!  Not only is a type already in our slot, but
+            someone has decorated it.  Complain and leave it alone. */
+         complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
        }
     }
 }
@@ -1208,7 +1495,7 @@ read_tag_pointer_type (dip)
   if ((utype = lookup_utype (dip -> die_ref)) == NULL)
     {
       utype = lookup_pointer_type (type);
-      (void) alloc_utype (dip -> die_ref, utype);
+      alloc_utype (dip -> die_ref, utype);
     }
   else
     {
@@ -1216,16 +1503,77 @@ read_tag_pointer_type (dip)
       TYPE_POINTER_TYPE (type) = utype;
 
       /* We assume the machine has only one representation for pointers!  */
-      /* FIXME:  This confuses host<->target data representations, and is a
-        poor assumption besides. */
-      
-      TYPE_LENGTH (utype) = sizeof (char *);
+      /* FIXME:  Possably a poor assumption  */
+      TYPE_LENGTH (utype) = TARGET_PTR_BIT / TARGET_CHAR_BIT ;
       TYPE_CODE (utype) = TYPE_CODE_PTR;
     }
 }
 
 /*
 
+LOCAL FUNCTION
+
+       read_tag_string_type -- read TAG_string_type DIE
+
+SYNOPSIS
+
+       static void read_tag_string_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+       Extract all information from a TAG_string_type DIE and add to
+       the user defined type vector.  It isn't really a user defined
+       type, but it behaves like one, with other DIE's using an
+       AT_user_def_type attribute to reference it.
+ */
+
+static void
+read_tag_string_type (dip)
+     struct dieinfo *dip;
+{
+  struct type *utype;
+  struct type *indextype;
+  struct type *rangetype;
+  unsigned long lowbound = 0;
+  unsigned long highbound;
+
+  if (dip -> has_at_byte_size)
+    {
+      /* A fixed bounds string */
+      highbound = dip -> at_byte_size - 1;
+    }
+  else
+    {
+      /* A varying length string.  Stub for now.  (FIXME) */
+      highbound = 1;
+    }
+  indextype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+  rangetype = create_range_type ((struct type *) NULL, indextype, lowbound,
+                                highbound);
+      
+  utype = lookup_utype (dip -> die_ref);
+  if (utype == NULL)
+    {
+      /* No type defined, go ahead and create a blank one to use. */
+      utype = alloc_utype (dip -> die_ref, (struct type *) NULL);
+    }
+  else
+    {
+      /* Already a type in our slot due to a forward reference. Make sure it
+        is a blank one.  If not, complain and leave it alone. */
+      if (TYPE_CODE (utype) != TYPE_CODE_UNDEF)
+       {
+         complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+         return;
+       }
+    }
+
+  /* Create the string type using the blank type we either found or created. */
+  utype = create_string_type (utype, rangetype);
+}
+
+/*
+
 LOCAL FUNCTION
 
        read_subroutine_type -- process TAG_subroutine_type dies
@@ -1272,17 +1620,20 @@ read_subroutine_type (dip, thisdie, enddie)
       /* This is the first reference to one of these types.  Make
         a new one and place it in the user defined types. */
       ftype = lookup_function_type (type);
-      (void) alloc_utype (dip -> die_ref, ftype);
+      alloc_utype (dip -> die_ref, ftype);
     }
-  else
+  else if (TYPE_CODE (ftype) == TYPE_CODE_UNDEF)
     {
       /* We have an existing partially constructed type, so bash it
         into the correct type. */
       TYPE_TARGET_TYPE (ftype) = type;
-      TYPE_FUNCTION_TYPE (type) = ftype;
       TYPE_LENGTH (ftype) = 1;
       TYPE_CODE (ftype) = TYPE_CODE_FUNC;
     }
+  else
+    {
+      complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+    }
 }
 
 /*
@@ -1319,9 +1670,14 @@ read_enumeration (dip, thisdie, enddie, objfile)
   struct symbol *sym;
   
   type = enum_type (dip, objfile);
-  if ((sym = new_symbol (dip, objfile)) != NULL)
+  sym = new_symbol (dip, objfile);
+  if (sym != NULL)
     {
       SYMBOL_TYPE (sym) = type;
+      if (cu_language == language_cplus)
+       {
+         synthesize_typedef (dip, objfile, type);
+       }
     }
 }
 
@@ -1375,6 +1731,7 @@ enum_type (dip, objfile)
   unsigned short blocksz;
   struct symbol *sym;
   int nbytes;
+  int unsigned_enum = 1;
   
   if ((type = lookup_utype (dip -> die_ref)) == NULL)
     {
@@ -1389,8 +1746,8 @@ enum_type (dip, objfile)
       && *dip -> at_name != '~'
       && *dip -> at_name != '.')
     {
-      TYPE_NAME (type) = obconcat (&objfile -> type_obstack, "enum",
-                                  ", dip -> at_name);
+      TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack,
+                                      "", "", dip -> at_name);
     }
   if (dip -> at_byte_size != 0)
     {
@@ -1414,34 +1771,40 @@ enum_type (dip, objfile)
          new = (struct nextfield *) alloca (sizeof (struct nextfield));
          new -> next = list;
          list = new;
-         list -> field.type = NULL;
-         list -> field.bitsize = 0;
-         list -> field.bitpos =
+         FIELD_TYPE (list->field) = NULL;
+         FIELD_BITSIZE (list->field) = 0;
+         FIELD_BITPOS (list->field) =
            target_to_host (scan, TARGET_FT_LONG_SIZE (objfile), GET_SIGNED,
                            objfile);
          scan += TARGET_FT_LONG_SIZE (objfile);
-         list -> field.name = savestring (scan, strlen (scan));
+         list -> field.name = obsavestring (scan, strlen (scan),
+                                            &objfile -> type_obstack);
          scan += strlen (scan) + 1;
          nfields++;
          /* Handcraft a new symbol for this enum member. */
          sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
                                                 sizeof (struct symbol));
-         (void) memset (sym, 0, sizeof (struct symbol));
+         memset (sym, 0, sizeof (struct symbol));
          SYMBOL_NAME (sym) = create_name (list -> field.name,
                                           &objfile->symbol_obstack);
+         SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
          SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
          SYMBOL_CLASS (sym) = LOC_CONST;
          SYMBOL_TYPE (sym) = type;
-         SYMBOL_VALUE (sym) = list -> field.bitpos;
+         SYMBOL_VALUE (sym) = FIELD_BITPOS (list->field);
+         if (SYMBOL_VALUE (sym) < 0)
+           unsigned_enum = 0;
          add_symbol_to_list (sym, list_in_scope);
        }
       /* Now create the vector of fields, and record how big it is. This is
-        where we reverse the order, by pulling the members of the list in
+        where we reverse the order, by pulling the members off the list in
         reverse order from how they were inserted.  If we have no fields
         (this is apparently possible in C++) then skip building a field
         vector. */
       if (nfields > 0)
        {
+         if (unsigned_enum)
+           TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
          TYPE_NFIELDS (type) = nfields;
          TYPE_FIELDS (type) = (struct field *)
            obstack_alloc (&objfile->symbol_obstack, sizeof (struct field) * nfields);
@@ -1485,6 +1848,16 @@ read_func_scope (dip, thisdie, enddie, objfile)
 {
   register struct context_stack *new;
   
+  /* AT_name is absent if the function is described with an
+     AT_abstract_origin tag.
+     Ignore the function description for now to avoid GDB core dumps.
+     FIXME: Add code to handle AT_abstract_origin tags properly.  */
+  if (dip -> at_name == NULL)
+    {
+      complain (&missing_at_name, DIE_ID);
+      return;
+    }
+
   if (objfile -> ei.entry_point >= dip -> at_low_pc &&
       objfile -> ei.entry_point <  dip -> at_high_pc)
     {
@@ -1507,6 +1880,59 @@ read_func_scope (dip, thisdie, enddie, objfile)
   list_in_scope = &file_symbols;
 }
 
+
+/*
+
+LOCAL FUNCTION
+
+       handle_producer -- process the AT_producer attribute
+
+DESCRIPTION
+
+       Perform any operations that depend on finding a particular
+       AT_producer attribute.
+
+ */
+
+static void
+handle_producer (producer)
+     char *producer;
+{
+
+  /* If this compilation unit was compiled with g++ or gcc, then set the
+     processing_gcc_compilation flag. */
+
+  if (STREQN (producer, GCC_PRODUCER, strlen (GCC_PRODUCER)))
+    {
+      char version = producer[strlen (GCC_PRODUCER)];
+      processing_gcc_compilation = (version == '2' ? 2 : 1);
+    }
+  else
+    {
+      processing_gcc_compilation =
+       STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER))
+       || STREQN (producer, CHILL_PRODUCER, strlen (CHILL_PRODUCER));
+    }
+
+  /* Select a demangling style if we can identify the producer and if
+     the current style is auto.  We leave the current style alone if it
+     is not auto.  We also leave the demangling style alone if we find a
+     gcc (cc1) producer, as opposed to a g++ (cc1plus) producer. */
+
+  if (AUTO_DEMANGLING)
+    {
+      if (STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)))
+       {
+         set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+       }
+      else if (STREQN (producer, LCC_PRODUCER, strlen (LCC_PRODUCER)))
+       {
+         set_demangling_style (LUCID_DEMANGLING_STYLE_STRING);
+       }
+    }
+}
+
+
 /*
 
 LOCAL FUNCTION
@@ -1545,35 +1971,27 @@ read_file_scope (dip, thisdie, enddie, objfile)
       objfile -> ei.entry_file_lowpc = dip -> at_low_pc;
       objfile -> ei.entry_file_highpc = dip -> at_high_pc;
     }
+  set_cu_language (dip);
   if (dip -> at_producer != NULL)
     {
-      processing_gcc_compilation =
-       STREQN (dip -> at_producer, GCC_PRODUCER, strlen (GCC_PRODUCER));
+      handle_producer (dip -> at_producer);
     }
   numutypes = (enddie - thisdie) / 4;
   utypes = (struct type **) xmalloc (numutypes * sizeof (struct type *));
-  back_to = make_cleanup (free, utypes);
-  (void) memset (utypes, 0, numutypes * sizeof (struct type *));
-  start_symtab (dip -> at_name, NULL, dip -> at_low_pc);
+  back_to = make_cleanup (free_utypes, NULL);
+  memset (utypes, 0, numutypes * sizeof (struct type *));
+  memset (ftypes, 0, FT_NUM_MEMBERS * sizeof (struct type *));
+  start_symtab (dip -> at_name, dip -> at_comp_dir, dip -> at_low_pc);
+  record_debugformat ("DWARF 1");
   decode_line_numbers (lnbase);
   process_dies (thisdie + dip -> die_length, enddie, objfile);
-  symtab = end_symtab (dip -> at_high_pc, 0, 0, objfile);
-  /* FIXME:  The following may need to be expanded for other languages */
-  switch (dip -> at_language)
+
+  symtab = end_symtab (dip -> at_high_pc, objfile, 0);
+  if (symtab != NULL)
     {
-      case LANG_C89:
-      case LANG_C:
-       symtab -> language = language_c;
-       break;
-      case LANG_C_PLUS_PLUS:
-       symtab -> language = language_cplus;
-       break;
-      default:
-       ;
-    }
+      symtab -> language = cu_language;
+    }      
   do_cleanups (back_to);
-  utypes = NULL;
-  numutypes = 0;
 }
 
 /*
@@ -1624,10 +2042,21 @@ process_dies (thisdie, enddie, objfile)
            {
              nextdie = thisdie + di.die_length;
            }
+#ifdef SMASH_TEXT_ADDRESS
+         /* I think that these are always text, not data, addresses.  */
+         SMASH_TEXT_ADDRESS (di.at_low_pc);
+         SMASH_TEXT_ADDRESS (di.at_high_pc);
+#endif
          switch (di.die_tag)
            {
            case TAG_compile_unit:
-             read_file_scope (&di, thisdie, nextdie, objfile);
+             /* Skip Tag_compile_unit if we are already inside a compilation
+                unit, we are unable to handle nested compilation units
+                properly (FIXME).  */
+             if (current_subfile == NULL)
+               read_file_scope (&di, thisdie, nextdie, objfile);
+             else
+               nextdie = thisdie + di.die_length;
              break;
            case TAG_global_subroutine:
            case TAG_subroutine:
@@ -1639,6 +2068,7 @@ process_dies (thisdie, enddie, objfile)
            case TAG_lexical_block:
              read_lexical_block_scope (&di, thisdie, nextdie, objfile);
              break;
+           case TAG_class_type:
            case TAG_structure_type:
            case TAG_union_type:
              read_structure_scope (&di, thisdie, nextdie, objfile);
@@ -1655,8 +2085,11 @@ process_dies (thisdie, enddie, objfile)
            case TAG_pointer_type:
              read_tag_pointer_type (&di);
              break;
+           case TAG_string_type:
+             read_tag_string_type (&di);
+             break;
            default:
-             (void) new_symbol (&di, objfile);
+             new_symbol (&di, objfile);
              break;
            }
        }
@@ -1771,20 +2204,23 @@ LOCAL FUNCTION
 
 SYNOPSIS
 
-       static int locval (char *loc)
+       static int locval (struct dieinfo *dip)
 
 DESCRIPTION
 
        Given pointer to a string of bytes that define a location, compute
        the location and return the value.
+       A location description containing no atoms indicates that the
+       object is optimized out. The optimized_out flag is set for those,
+       the return value is meaningless.
 
        When computing values involving the current value of the frame pointer,
        the value zero is used, which results in a value relative to the frame
        pointer, rather than the absolute value.  This is what GDB wants
        anyway.
     
-       When the result is a register number, the global isreg flag is set,
-       otherwise it is cleared.  This is a kludge until we figure out a better
+       When the result is a register number, the isreg flag is set, otherwise
+       it is cleared.  This is a kludge until we figure out a better
        way to handle the problem.  Gdb's design does not mesh well with the
        DWARF notion of a location computing interpreter, which is a shame
        because the flexibility goes unused.
@@ -1796,29 +2232,32 @@ NOTES
  */
 
 static int
-locval (loc)
-     char *loc;
+locval (dip)
+     struct dieinfo *dip;
 {
   unsigned short nbytes;
   unsigned short locsize;
   auto long stack[64];
   int stacki;
+  char *loc;
   char *end;
-  long regno;
   int loc_atom_code;
   int loc_value_size;
   
+  loc = dip -> at_location;
   nbytes = attribute_size (AT_location);
   locsize = target_to_host (loc, nbytes, GET_UNSIGNED, current_objfile);
   loc += nbytes;
   end = loc + locsize;
   stacki = 0;
   stack[stacki] = 0;
-  isreg = 0;
-  offreg = 0;
+  dip -> isreg = 0;
+  dip -> offreg = 0;
+  dip -> optimized_out = 1;
   loc_value_size = TARGET_FT_LONG_SIZE (current_objfile);
   while (loc < end)
     {
+      dip -> optimized_out = 0;
       loc_atom_code = target_to_host (loc, SIZEOF_LOC_ATOM_CODE, GET_UNSIGNED,
                                      current_objfile);
       loc += SIZEOF_LOC_ATOM_CODE;
@@ -1830,27 +2269,22 @@ locval (loc)
            break;
          case OP_REG:
            /* push register (number) */
-           stack[++stacki] = target_to_host (loc, loc_value_size,
-                                             GET_UNSIGNED, current_objfile);
+           stack[++stacki]
+             = DWARF_REG_TO_REGNUM (target_to_host (loc, loc_value_size,
+                                                    GET_UNSIGNED,
+                                                    current_objfile));
            loc += loc_value_size;
-           isreg = 1;
+           dip -> isreg = 1;
            break;
          case OP_BASEREG:
            /* push value of register (number) */
-           /* Actually, we compute the value as if register has 0 */
-           offreg = 1;
-           regno = target_to_host (loc, loc_value_size, GET_UNSIGNED,
-                                   current_objfile);
+           /* Actually, we compute the value as if register has 0, so the
+              value ends up being the offset from that register.  */
+           dip -> offreg = 1;
+           dip -> basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED,
+                                            current_objfile);
            loc += loc_value_size;
-           if (regno == R_FP)
-             {
-               stack[++stacki] = 0;
-             }
-           else
-             {
-               stack[++stacki] = 0;
-               SQUAWK (("BASEREG %d not handled!", regno));
-             }
+           stack[++stacki] = 0;
            break;
          case OP_ADDR:
            /* push address (relocated address) */
@@ -1866,10 +2300,10 @@ locval (loc)
            break;
          case OP_DEREF2:
            /* pop, deref and push 2 bytes (as a long) */
-           SQUAWK (("OP_DEREF2 address 0x%x not handled", stack[stacki]));
+           complain (&op_deref2, DIE_ID, DIE_NAME, stack[stacki]);
            break;
          case OP_DEREF4:       /* pop, deref and push 4 bytes (as a long) */
-           SQUAWK (("OP_DEREF4 address 0x%x not handled", stack[stacki]));
+           complain (&op_deref4, DIE_ID, DIE_NAME, stack[stacki]);
            break;
          case OP_ADD:  /* pop top 2 items, add, push result */
            stack[stacki - 1] += stack[stacki];
@@ -1888,25 +2322,24 @@ LOCAL FUNCTION
 
 SYNOPSIS
 
-       static struct symtab *read_ofile_symtab (struct partial_symtab *pst)
+       static void read_ofile_symtab (struct partial_symtab *pst)
 
 DESCRIPTION
 
        When expanding a partial symbol table entry to a full symbol table
        entry, this is the function that gets called to read in the symbols
-       for the compilation unit.
-
-       Returns a pointer to the newly constructed symtab (which is now
-       the new first one on the objfile's symtab list).
+       for the compilation unit.  A pointer to the newly constructed symtab,
+       which is now the new first one on the objfile's symtab list, is
+       stashed in the partial symbol table entry.
  */
 
-static struct symtab *
+static void
 read_ofile_symtab (pst)
      struct partial_symtab *pst;
 {
   struct cleanup *back_to;
   unsigned long lnsize;
-  int foffset;
+  file_ptr foffset;
   bfd *abfd;
   char lnsizedata[SIZEOF_LINETBL_LENGTH];
 
@@ -1917,12 +2350,14 @@ read_ofile_symtab (pst)
      unit, seek to the location in the file, and read in all the DIE's. */
 
   diecount = 0;
-  dbbase = xmalloc (DBLENGTH(pst));
+  dbsize = DBLENGTH (pst);
+  dbbase = xmalloc (dbsize);
   dbroff = DBROFF(pst);
   foffset = DBFOFF(pst) + dbroff;
-  baseaddr = pst -> addr;
-  if (bfd_seek (abfd, foffset, 0) ||
-      (bfd_read (dbbase, DBLENGTH(pst), 1, abfd) != DBLENGTH(pst)))
+  base_section_offsets = pst->section_offsets;
+  baseaddr = ANOFFSET (pst->section_offsets, 0);
+  if (bfd_seek (abfd, foffset, SEEK_SET) ||
+      (bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
     {
       free (dbbase);
       error ("can't read DWARF data");
@@ -1937,7 +2372,7 @@ read_ofile_symtab (pst)
   lnbase = NULL;
   if (LNFOFF (pst))
     {
-      if (bfd_seek (abfd, LNFOFF (pst), 0) ||
+      if (bfd_seek (abfd, LNFOFF (pst), SEEK_SET) ||
          (bfd_read ((PTR) lnsizedata, sizeof (lnsizedata), 1, abfd) !=
           sizeof (lnsizedata)))
        {
@@ -1946,7 +2381,7 @@ read_ofile_symtab (pst)
       lnsize = target_to_host (lnsizedata, SIZEOF_LINETBL_LENGTH,
                               GET_UNSIGNED, pst -> objfile);
       lnbase = xmalloc (lnsize);
-      if (bfd_seek (abfd, LNFOFF (pst), 0) ||
+      if (bfd_seek (abfd, LNFOFF (pst), SEEK_SET) ||
          (bfd_read (lnbase, lnsize, 1, abfd) != lnsize))
        {
          free (lnbase);
@@ -1955,10 +2390,10 @@ read_ofile_symtab (pst)
       make_cleanup (free, lnbase);
     }
 
-  process_dies (dbbase, dbbase + DBLENGTH(pst), pst -> objfile);
+  process_dies (dbbase, dbbase + dbsize, pst -> objfile);
   do_cleanups (back_to);
   current_objfile = NULL;
-  return (pst -> objfile -> symtabs);
+  pst -> symtab = pst -> objfile -> symtabs;
 }
 
 /*
@@ -1983,6 +2418,7 @@ psymtab_to_symtab_1 (pst)
      struct partial_symtab *pst;
 {
   int i;
+  struct cleanup *old_chain;
   
   if (pst != NULL)
     {
@@ -2001,28 +2437,32 @@ psymtab_to_symtab_1 (pst)
                  /* Inform about additional files that need to be read in. */
                  if (info_verbose)
                    {
-                     fputs_filtered (" ", stdout);
+                     fputs_filtered (" ", gdb_stdout);
                      wrap_here ("");
-                     fputs_filtered ("and ", stdout);
+                     fputs_filtered ("and ", gdb_stdout);
                      wrap_here ("");
                      printf_filtered ("%s...",
                                       pst -> dependencies[i] -> filename);
                      wrap_here ("");
-                     fflush (stdout);          /* Flush output */
+                     gdb_flush (gdb_stdout);           /* Flush output */
                    }
                  psymtab_to_symtab_1 (pst -> dependencies[i]);
                }
            }     
          if (DBLENGTH (pst))           /* Otherwise it's a dummy */
            {
-             pst -> symtab = read_ofile_symtab (pst);
+             buildsym_init ();
+             old_chain = make_cleanup ((make_cleanup_func) 
+                                        really_free_pendings, 0);
+             read_ofile_symtab (pst);
              if (info_verbose)
                {
                  printf_filtered ("%d DIE's, sorting...", diecount);
                  wrap_here ("");
-                 fflush (stdout);
+                 gdb_flush (gdb_stdout);
                }
              sort_symtab_syms (pst -> symtab);
+             do_cleanups (old_chain);
            }
          pst -> readin = 1;
        }
@@ -2069,7 +2509,7 @@ dwarf_psymtab_to_symtab (pst)
                {
                  printf_filtered ("Reading in symbols for %s...",
                                   pst -> filename);
-                 fflush (stdout);
+                 gdb_flush (gdb_stdout);
                }
              
              psymtab_to_symtab_1 (pst);
@@ -2087,7 +2527,7 @@ dwarf_psymtab_to_symtab (pst)
              if (info_verbose)
                {
                  printf_filtered ("done.\n");
-                 fflush (stdout);
+                 gdb_flush (gdb_stdout);
                }
            }
        }
@@ -2096,54 +2536,6 @@ dwarf_psymtab_to_symtab (pst)
 
 /*
 
-LOCAL FUNCTION
-
-       init_psymbol_list -- initialize storage for partial symbols
-
-SYNOPSIS
-
-       static void init_psymbol_list (struct objfile *objfile, int total_symbols)
-
-DESCRIPTION
-
-       Initializes storage for all of the partial symbols that will be
-       created by dwarf_build_psymtabs and subsidiaries.
- */
-
-static void
-init_psymbol_list (objfile, total_symbols)
-     struct objfile *objfile;
-     int total_symbols;
-{
-  /* Free any previously allocated psymbol lists.  */
-  
-  if (objfile -> global_psymbols.list)
-    {
-      mfree (objfile -> md, (PTR)objfile -> global_psymbols.list);
-    }
-  if (objfile -> static_psymbols.list)
-    {
-      mfree (objfile -> md, (PTR)objfile -> static_psymbols.list);
-    }
-  
-  /* Current best guess is that there are approximately a twentieth
-     of the total symbols (in a debugging file) are global or static
-     oriented symbols */
-  
-  objfile -> global_psymbols.size = total_symbols / 10;
-  objfile -> static_psymbols.size = total_symbols / 10;
-  objfile -> global_psymbols.next =
-    objfile -> global_psymbols.list = (struct partial_symbol *)
-      xmmalloc (objfile -> md, objfile -> global_psymbols.size
-                            * sizeof (struct partial_symbol));
-  objfile -> static_psymbols.next =
-    objfile -> static_psymbols.list = (struct partial_symbol *)
-      xmmalloc (objfile -> md, objfile -> static_psymbols.size
-                            * sizeof (struct partial_symbol));
-}
-
-/*
-
 LOCAL FUNCTION
 
        add_enum_psymbol -- add enumeration members to partial symbol table
@@ -2181,8 +2573,9 @@ add_enum_psymbol (dip, objfile)
       while (scan < listend)
        {
          scan += TARGET_FT_LONG_SIZE (objfile);
-         ADD_PSYMBOL_TO_LIST (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST,
-                              objfile -> static_psymbols, 0);
+         add_psymbol_to_list (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST,
+                              &objfile -> static_psymbols, 0, 0, cu_language,
+                              objfile);
          scan += strlen (scan) + 1;
        }
     }
@@ -2200,6 +2593,9 @@ DESCRIPTION
        add to a partial symbol table, finish filling in the die info
        and then add a partial symbol table entry for it.
 
+NOTES
+
+       The caller must ensure that the DIE has a valid name attribute.
 */
 
 static void
@@ -2210,55 +2606,54 @@ add_partial_symbol (dip, objfile)
   switch (dip -> die_tag)
     {
     case TAG_global_subroutine:
-      record_minimal_symbol (dip -> at_name, dip -> at_low_pc, mst_text,
-                           objfile);
-      ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
-                          VAR_NAMESPACE, LOC_BLOCK,
-                          objfile -> global_psymbols,
-                          dip -> at_low_pc);
+      add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
+                               VAR_NAMESPACE, LOC_BLOCK,
+                               &objfile -> global_psymbols,
+                               0, dip -> at_low_pc, cu_language, objfile);
       break;
     case TAG_global_variable:
-      record_minimal_symbol (dip -> at_name, locval (dip -> at_location),
-                           mst_data, objfile);
-      ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+      add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
                           VAR_NAMESPACE, LOC_STATIC,
-                          objfile -> global_psymbols,
-                          0);
+                          &objfile -> global_psymbols,
+                          0, 0, cu_language, objfile);
       break;
     case TAG_subroutine:
-      ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
-                          VAR_NAMESPACE, LOC_BLOCK,
-                          objfile -> static_psymbols,
-                          dip -> at_low_pc);
+      add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
+                               VAR_NAMESPACE, LOC_BLOCK,
+                               &objfile -> static_psymbols,
+                               0, dip -> at_low_pc, cu_language, objfile);
       break;
     case TAG_local_variable:
-      ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+      add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
                           VAR_NAMESPACE, LOC_STATIC,
-                          objfile -> static_psymbols,
-                          0);
+                          &objfile -> static_psymbols,
+                          0, 0, cu_language, objfile);
       break;
     case TAG_typedef:
-      ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+      add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
                           VAR_NAMESPACE, LOC_TYPEDEF,
-                          objfile -> static_psymbols,
-                          0);
+                          &objfile -> static_psymbols,
+                          0, 0, cu_language, objfile);
       break;
+    case TAG_class_type:
     case TAG_structure_type:
     case TAG_union_type:
-      ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
-                          STRUCT_NAMESPACE, LOC_TYPEDEF,
-                          objfile -> static_psymbols,
-                          0);
-      break;
     case TAG_enumeration_type:
-      if (dip -> at_name)
+      /* Do not add opaque aggregate definitions to the psymtab.  */
+      if (!dip -> has_at_byte_size)
+       break;
+      add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
+                          STRUCT_NAMESPACE, LOC_TYPEDEF,
+                          &objfile -> static_psymbols,
+                          0, 0, cu_language, objfile);
+      if (cu_language == language_cplus)
        {
-         ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
-                              STRUCT_NAMESPACE, LOC_TYPEDEF,
-                              objfile -> static_psymbols,
-                              0);
+         /* For C++, these implicitly act as typedefs as well. */
+         add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
+                              VAR_NAMESPACE, LOC_TYPEDEF,
+                              &objfile -> static_psymbols,
+                              0, 0, cu_language, objfile);
        }
-      add_enum_psymbol (dip, objfile);
       break;
     }
 }
@@ -2273,15 +2668,50 @@ DESCRIPTION
 
        Process the DIE's within a single compilation unit, looking for
        interesting DIE's that contribute to the partial symbol table entry
-       for this compilation unit.  Since we cannot follow any sibling
-       chains without reading the complete DIE info for every DIE,
-       it is probably faster to just sequentially check each one to
-       see if it is one of the types we are interested in, and if so,
-       then extract all the attributes info and generate a partial
-       symbol table entry.
+       for this compilation unit.
 
 NOTES
 
+       There are some DIE's that may appear both at file scope and within
+       the scope of a function.  We are only interested in the ones at file
+       scope, and the only way to tell them apart is to keep track of the
+       scope.  For example, consider the test case:
+
+               static int i;
+               main () { int j; }
+
+       for which the relevant DWARF segment has the structure:
+       
+               0x51:
+               0x23   global subrtn   sibling     0x9b
+                                      name        main
+                                      fund_type   FT_integer
+                                      low_pc      0x800004cc
+                                      high_pc     0x800004d4
+                                           
+               0x74:
+               0x23   local var       sibling     0x97
+                                      name        j
+                                      fund_type   FT_integer
+                                      location    OP_BASEREG 0xe
+                                                  OP_CONST 0xfffffffc
+                                                  OP_ADD
+               0x97:
+               0x4         
+               
+               0x9b:
+               0x1d   local var       sibling     0xb8
+                                      name        i
+                                      fund_type   FT_integer
+                                      location    OP_ADDR 0x800025dc
+                                           
+               0xb8:
+               0x4         
+
+       We want to include the symbol 'i' in the partial symbol table, but
+       not the symbol 'j'.  In essence, we want to skip all the dies within
+       the scope of a TAG_global_subroutine DIE.
+
        Don't attempt to add anonymous structures or unions since they have
        no name.  Anonymous enumerations however are processed, because we
        want to extract their member names (the check for a tag name is
@@ -2299,6 +2729,7 @@ scan_partial_symbols (thisdie, enddie, objfile)
      struct objfile *objfile;
 {
   char *nextdie;
+  char *temp;
   struct dieinfo di;
   
   while (thisdie < enddie)
@@ -2317,6 +2748,29 @@ scan_partial_symbols (thisdie, enddie, objfile)
            {
            case TAG_global_subroutine:
            case TAG_subroutine:
+             completedieinfo (&di, objfile);
+             if (di.at_name && (di.has_at_low_pc || di.at_location))
+               {
+                 add_partial_symbol (&di, objfile);
+                 /* If there is a sibling attribute, adjust the nextdie
+                    pointer to skip the entire scope of the subroutine.
+                    Apply some sanity checking to make sure we don't 
+                    overrun or underrun the range of remaining DIE's */
+                 if (di.at_sibling != 0)
+                   {
+                     temp = dbbase + di.at_sibling - dbroff;
+                     if ((temp < thisdie) || (temp >= enddie))
+                       {
+                         complain (&bad_die_ref, DIE_ID, DIE_NAME,
+                                   di.at_sibling);
+                       }
+                     else
+                       {
+                         nextdie = temp;
+                       }
+                   }
+               }
+             break;
            case TAG_global_variable:
            case TAG_local_variable:
              completedieinfo (&di, objfile);
@@ -2326,6 +2780,7 @@ scan_partial_symbols (thisdie, enddie, objfile)
                }
              break;
            case TAG_typedef:
+           case TAG_class_type:
            case TAG_structure_type:
            case TAG_union_type:
              completedieinfo (&di, objfile);
@@ -2336,7 +2791,11 @@ scan_partial_symbols (thisdie, enddie, objfile)
              break;
            case TAG_enumeration_type:
              completedieinfo (&di, objfile);
-             add_partial_symbol (&di, objfile);
+             if (di.at_name)
+               {
+                 add_partial_symbol (&di, objfile);
+               }
+             add_enum_psymbol (&di, objfile);
              break;
            }
        }
@@ -2388,12 +2847,11 @@ RETURNS
  */
 
 static void
-scan_compilation_units (filename, thisdie, enddie, dbfoff, lnoffset, objfile)
-     char *filename;
+scan_compilation_units (thisdie, enddie, dbfoff, lnoffset, objfile)
      char *thisdie;
      char *enddie;
-     unsigned int dbfoff;
-     unsigned int lnoffset;
+     file_ptr dbfoff;
+     file_ptr lnoffset;
      struct objfile *objfile;
 {
   char *nextdie;
@@ -2401,7 +2859,7 @@ scan_compilation_units (filename, thisdie, enddie, dbfoff, lnoffset, objfile)
   struct partial_symtab *pst;
   int culength;
   int curoff;
-  int curlnoffset;
+  file_ptr curlnoffset;
 
   while (thisdie < enddie)
     {
@@ -2417,6 +2875,7 @@ scan_compilation_units (filename, thisdie, enddie, dbfoff, lnoffset, objfile)
       else
        {
          completedieinfo (&di, objfile);
+         set_cu_language (&di);
          if (di.at_sibling != 0)
            {
              nextdie = dbbase + di.at_sibling - dbroff;
@@ -2431,8 +2890,8 @@ scan_compilation_units (filename, thisdie, enddie, dbfoff, lnoffset, objfile)
 
          /* First allocate a new partial symbol table structure */
 
-         pst = start_psymtab_common (objfile, baseaddr, di.at_name,
-                                     di.at_low_pc,
+         pst = start_psymtab_common (objfile, base_section_offsets,
+                                     di.at_name, di.at_low_pc,
                                      objfile -> global_psymbols.next,
                                      objfile -> static_psymbols.next);
 
@@ -2493,22 +2952,34 @@ new_symbol (dip, objfile)
     {
       sym = (struct symbol *) obstack_alloc (&objfile -> symbol_obstack,
                                             sizeof (struct symbol));
-      (void) memset (sym, 0, sizeof (struct symbol));
-      SYMBOL_NAME (sym) = create_name (dip -> at_name, &objfile->symbol_obstack);
+      OBJSTAT (objfile, n_syms++);
+      memset (sym, 0, sizeof (struct symbol));
+      SYMBOL_NAME (sym) = create_name (dip -> at_name,
+                                      &objfile->symbol_obstack);
       /* default assumptions */
       SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
       SYMBOL_CLASS (sym) = LOC_STATIC;
       SYMBOL_TYPE (sym) = decode_die_type (dip);
+
+      /* If this symbol is from a C++ compilation, then attempt to cache the
+        demangled form for future reference.  This is a typical time versus
+        space tradeoff, that was decided in favor of time because it sped up
+        C++ symbol lookups by a factor of about 20. */
+
+      SYMBOL_LANGUAGE (sym) = cu_language;
+      SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile -> symbol_obstack);
       switch (dip -> die_tag)
        {
        case TAG_label:
-         SYMBOL_VALUE (sym) = dip -> at_low_pc;
+         SYMBOL_VALUE_ADDRESS (sym) = dip -> at_low_pc;
          SYMBOL_CLASS (sym) = LOC_LABEL;
          break;
        case TAG_global_subroutine:
        case TAG_subroutine:
-         SYMBOL_VALUE (sym) = dip -> at_low_pc;
+         SYMBOL_VALUE_ADDRESS (sym) = dip -> at_low_pc;
          SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym));
+         if (dip -> at_prototyped)
+           TYPE_FLAGS (SYMBOL_TYPE (sym)) |= TYPE_FLAG_PROTOTYPED;
          SYMBOL_CLASS (sym) = LOC_BLOCK;
          if (dip -> die_tag == TAG_global_subroutine)
            {
@@ -2522,7 +2993,7 @@ new_symbol (dip, objfile)
        case TAG_global_variable:
          if (dip -> at_location != NULL)
            {
-             SYMBOL_VALUE (sym) = locval (dip -> at_location);
+             SYMBOL_VALUE_ADDRESS (sym) = locval (dip);
              add_symbol_to_list (sym, &global_symbols);
              SYMBOL_CLASS (sym) = LOC_STATIC;
              SYMBOL_VALUE (sym) += baseaddr;
@@ -2531,33 +3002,53 @@ new_symbol (dip, objfile)
        case TAG_local_variable:
          if (dip -> at_location != NULL)
            {
-             SYMBOL_VALUE (sym) = locval (dip -> at_location);
-             add_symbol_to_list (sym, list_in_scope);
-             if (isreg)
+             int loc = locval (dip);
+             if (dip -> optimized_out)
+               {
+                 SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
+               }
+             else if (dip -> isreg)
                {
                  SYMBOL_CLASS (sym) = LOC_REGISTER;
                }
-             else if (offreg)
+             else if (dip -> offreg)
                {
-                 SYMBOL_CLASS (sym) = LOC_LOCAL;
+                 SYMBOL_CLASS (sym) = LOC_BASEREG;
+                 SYMBOL_BASEREG (sym) = dip -> basereg;
                }
              else
                {
                  SYMBOL_CLASS (sym) = LOC_STATIC;
                  SYMBOL_VALUE (sym) += baseaddr;
                }
+             if (SYMBOL_CLASS (sym) == LOC_STATIC)
+               {
+                 /* LOC_STATIC address class MUST use SYMBOL_VALUE_ADDRESS,
+                    which may store to a bigger location than SYMBOL_VALUE. */
+                 SYMBOL_VALUE_ADDRESS (sym) = loc;
+               }
+             else
+               {
+                 SYMBOL_VALUE (sym) = loc;
+               }
+             add_symbol_to_list (sym, list_in_scope);
            }
          break;
        case TAG_formal_parameter:
          if (dip -> at_location != NULL)
            {
-             SYMBOL_VALUE (sym) = locval (dip -> at_location);
+             SYMBOL_VALUE (sym) = locval (dip);
            }
          add_symbol_to_list (sym, list_in_scope);
-         if (isreg)
+         if (dip -> isreg)
            {
              SYMBOL_CLASS (sym) = LOC_REGPARM;
            }
+         else if (dip -> offreg)
+           {
+             SYMBOL_CLASS (sym) = LOC_BASEREG_ARG;
+             SYMBOL_BASEREG (sym) = dip -> basereg;
+           }
          else
            {
              SYMBOL_CLASS (sym) = LOC_ARG;
@@ -2567,6 +3058,7 @@ new_symbol (dip, objfile)
          /* From varargs functions; gdb doesn't seem to have any interest in
             this information, so just ignore it for now. (FIXME?) */
          break;
+       case TAG_class_type:
        case TAG_structure_type:
        case TAG_union_type:
        case TAG_enumeration_type:
@@ -2591,6 +3083,52 @@ new_symbol (dip, objfile)
 
 /*
 
+LOCAL FUNCTION
+
+       synthesize_typedef -- make a symbol table entry for a "fake" typedef
+
+SYNOPSIS
+
+       static void synthesize_typedef (struct dieinfo *dip,
+                                       struct objfile *objfile,
+                                       struct type *type);
+
+DESCRIPTION
+
+       Given a pointer to a DWARF information entry, synthesize a typedef
+       for the name in the DIE, using the specified type.
+
+       This is used for C++ class, structs, unions, and enumerations to
+       set up the tag name as a type.
+
+ */
+
+static void
+synthesize_typedef (dip, objfile, type)
+     struct dieinfo *dip;
+     struct objfile *objfile;
+     struct type *type;
+{
+  struct symbol *sym = NULL;
+  
+  if (dip -> at_name != NULL)
+    {
+      sym = (struct symbol *)
+       obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+      OBJSTAT (objfile, n_syms++);
+      memset (sym, 0, sizeof (struct symbol));
+      SYMBOL_NAME (sym) = create_name (dip -> at_name,
+                                      &objfile->symbol_obstack);
+      SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+      SYMBOL_TYPE (sym) = type;
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, list_in_scope);
+    }
+}
+
+/*
+
 LOCAL FUNCTION
 
        decode_mod_fund_type -- decode a modified fundamental type
@@ -2691,7 +3229,7 @@ LOCAL FUNCTION
 
 SYNOPSIS
 
-       static struct type *decode_modified_type (unsigned char *modifiers,
+       static struct type *decode_modified_type (char *modifiers,
            unsigned short modcount, int mtype)
 
 DESCRIPTION
@@ -2725,14 +3263,14 @@ BUGS
 
 static struct type *
 decode_modified_type (modifiers, modcount, mtype)
-     unsigned char *modifiers;
+     char *modifiers;
      unsigned int modcount;
      int mtype;
 {
   struct type *typep = NULL;
   unsigned short fundtype;
   DIE_REF die_ref;
-  unsigned char modifier;
+  char modifier;
   int nbytes;
   
   if (modcount == 0)
@@ -2755,8 +3293,8 @@ decode_modified_type (modifiers, modcount, mtype)
            }
          break;
        default:
-         SQUAWK (("botched modified type decoding (mtype 0x%x)", mtype));
-         typep = lookup_fundamental_type (current_objfile, FT_INTEGER);
+         complain (&botched_modified_type, DIE_ID, DIE_NAME, mtype);
+         typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
          break;
        }
     }
@@ -2773,15 +3311,16 @@ decode_modified_type (modifiers, modcount, mtype)
            typep = lookup_reference_type (typep);
            break;
          case MOD_const:
-           SQUAWK (("type modifier 'const' ignored"));         /* FIXME */
+           complain (&const_ignored, DIE_ID, DIE_NAME);  /* FIXME */
            break;
          case MOD_volatile:
-           SQUAWK (("type modifier 'volatile' ignored"));      /* FIXME */
+           complain (&volatile_ignored, DIE_ID, DIE_NAME); /* FIXME */
            break;
          default:
-           if (!(MOD_lo_user <= modifier && modifier <= MOD_hi_user))
+           if (!(MOD_lo_user <= (unsigned char) modifier
+                 && (unsigned char) modifier <= MOD_hi_user))
              {
-               SQUAWK (("unknown type modifier %u", modifier));
+               complain (&unknown_type_modifier, DIE_ID, DIE_NAME, modifier);
              }
            break;
        }
@@ -2803,10 +3342,12 @@ DESCRIPTION
 
 NOTES
 
-       If we encounter a fundamental type that we are unprepared to
-       deal with, and it is not in the range of those types defined
-       as application specific types, then we issue a warning and
-       treat the type as an "int".
+       For robustness, if we are asked to translate a fundamental
+       type that we are unprepared to deal with, we return int so
+       callers can always depend upon a valid type being returned,
+       and so gdb may at least do something reasonable by default.
+       If the type is not in the range of those types defined as
+       application specific types, we also issue a warning.
 */
 
 static struct type *
@@ -2819,108 +3360,111 @@ decode_fund_type (fundtype)
     {
 
     case FT_void:
-      typep = lookup_fundamental_type (current_objfile, FT_VOID);
+      typep = dwarf_fundamental_type (current_objfile, FT_VOID);
       break;
     
     case FT_boolean:           /* Was FT_set in AT&T version */
-      typep = lookup_fundamental_type (current_objfile, FT_BOOLEAN);
+      typep = dwarf_fundamental_type (current_objfile, FT_BOOLEAN);
       break;
 
     case FT_pointer:           /* (void *) */
-      typep = lookup_fundamental_type (current_objfile, FT_VOID);
+      typep = dwarf_fundamental_type (current_objfile, FT_VOID);
       typep = lookup_pointer_type (typep);
       break;
     
     case FT_char:
-      typep = lookup_fundamental_type (current_objfile, FT_CHAR);
+      typep = dwarf_fundamental_type (current_objfile, FT_CHAR);
       break;
     
     case FT_signed_char:
-      typep = lookup_fundamental_type (current_objfile, FT_SIGNED_CHAR);
+      typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_CHAR);
       break;
 
     case FT_unsigned_char:
-      typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+      typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
       break;
     
     case FT_short:
-      typep = lookup_fundamental_type (current_objfile, FT_SHORT);
+      typep = dwarf_fundamental_type (current_objfile, FT_SHORT);
       break;
 
     case FT_signed_short:
-      typep = lookup_fundamental_type (current_objfile, FT_SIGNED_SHORT);
+      typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_SHORT);
       break;
     
     case FT_unsigned_short:
-      typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
+      typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
       break;
     
     case FT_integer:
-      typep = lookup_fundamental_type (current_objfile, FT_INTEGER);
+      typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
       break;
 
     case FT_signed_integer:
-      typep = lookup_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
+      typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
       break;
     
     case FT_unsigned_integer:
-      typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+      typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
       break;
     
     case FT_long:
-      typep = lookup_fundamental_type (current_objfile, FT_LONG);
+      typep = dwarf_fundamental_type (current_objfile, FT_LONG);
       break;
 
     case FT_signed_long:
-      typep = lookup_fundamental_type (current_objfile, FT_SIGNED_LONG);
+      typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG);
       break;
     
     case FT_unsigned_long:
-      typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
+      typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
       break;
     
     case FT_long_long:
-      typep = lookup_fundamental_type (current_objfile, FT_LONG_LONG);
+      typep = dwarf_fundamental_type (current_objfile, FT_LONG_LONG);
       break;
 
     case FT_signed_long_long:
-      typep = lookup_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG);
+      typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG);
       break;
 
     case FT_unsigned_long_long:
-      typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG);
+      typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG);
       break;
 
     case FT_float:
-      typep = lookup_fundamental_type (current_objfile, FT_FLOAT);
+      typep = dwarf_fundamental_type (current_objfile, FT_FLOAT);
       break;
     
     case FT_dbl_prec_float:
-      typep = lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
+      typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
       break;
     
     case FT_ext_prec_float:
-      typep = lookup_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT);
+      typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT);
       break;
     
     case FT_complex:
-      typep = lookup_fundamental_type (current_objfile, FT_COMPLEX);
+      typep = dwarf_fundamental_type (current_objfile, FT_COMPLEX);
       break;
     
     case FT_dbl_prec_complex:
-      typep = lookup_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX);
+      typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX);
       break;
     
     case FT_ext_prec_complex:
-      typep = lookup_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX);
+      typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX);
       break;
     
     }
 
-  if ((typep == NULL) && !(FT_lo_user <= fundtype && fundtype <= FT_hi_user))
+  if (typep == NULL)
     {
-      SQUAWK (("unexpected fundamental type 0x%x", fundtype));
-      typep = lookup_fundamental_type (current_objfile, FT_VOID);
+      typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+      if (!(FT_lo_user <= fundtype && fundtype <= FT_hi_user))
+       {
+         complain (&unexpected_fund_type, DIE_ID, DIE_NAME, fundtype);
+       }
     }
     
   return (typep);
@@ -2949,7 +3493,7 @@ create_name (name, obstackp)
 
   length = strlen (name) + 1;
   newname = (char *) obstack_alloc (obstackp, length);
-  (void) strcpy (newname, name);
+  strcpy (newname, name);
   return (newname);
 }
 
@@ -2999,6 +3543,12 @@ NOTES
        that if a padding DIE is used for alignment and the amount needed is
        less than SIZEOF_DIE_LENGTH, then the padding DIE has to be big
        enough to align to the next alignment boundry.
+
+       We do some basic sanity checking here, such as verifying that the
+       length of the die would not cause it to overrun the recorded end of
+       the buffer holding the DIE info.  If we find a DIE that is either
+       too small or too large, we force it's length to zero which should
+       cause the caller to take appropriate action.
  */
 
 static void
@@ -3008,14 +3558,16 @@ basicdieinfo (dip, diep, objfile)
      struct objfile *objfile;
 {
   curdie = dip;
-  (void) memset (dip, 0, sizeof (struct dieinfo));
+  memset (dip, 0, sizeof (struct dieinfo));
   dip -> die = diep;
   dip -> die_ref = dbroff + (diep - dbbase);
   dip -> die_length = target_to_host (diep, SIZEOF_DIE_LENGTH, GET_UNSIGNED,
                                      objfile);
-  if (dip -> die_length < SIZEOF_DIE_LENGTH)
+  if ((dip -> die_length < SIZEOF_DIE_LENGTH) ||
+      ((diep + dip -> die_length) > (dbbase + dbsize)))
     {
-      dwarfwarn ("malformed DIE, bad length (%d bytes)", dip -> die_length);
+      complain (&malformed_die, DIE_ID, DIE_NAME, dip -> die_length);
+      dip -> die_length = 0;
     }
   else if (dip -> die_length < (SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG))
     {
@@ -3082,7 +3634,7 @@ completedieinfo (dip, objfile)
       diep += SIZEOF_ATTRIBUTE;
       if ((nbytes = attribute_size (attr)) == -1)
        {
-         SQUAWK (("unknown attribute length, skipped remaining attributes"));;
+         complain (&unknown_attribute_length, DIE_ID, DIE_NAME);
          diep = end;
          continue;
        }
@@ -3100,10 +3652,6 @@ completedieinfo (dip, objfile)
          dip -> at_bit_offset = target_to_host (diep, nbytes, GET_UNSIGNED,
                                                 objfile);
          break;
-       case AT_visibility:
-         dip -> at_visibility = target_to_host (diep, nbytes, GET_UNSIGNED,
-                                                objfile);
-         break;
        case AT_sibling:
          dip -> at_sibling = target_to_host (diep, nbytes, GET_UNSIGNED,
                                              objfile);
@@ -3135,6 +3683,7 @@ completedieinfo (dip, objfile)
        case AT_byte_size:
          dip -> at_byte_size = target_to_host (diep, nbytes, GET_UNSIGNED,
                                                objfile);
+         dip -> has_at_byte_size = 1;
          break;
        case AT_bit_size:
          dip -> at_bit_size = target_to_host (diep, nbytes, GET_UNSIGNED,
@@ -3148,10 +3697,6 @@ completedieinfo (dip, objfile)
          dip -> at_discr = target_to_host (diep, nbytes, GET_UNSIGNED,
                                            objfile);
          break;
-       case AT_import:
-         dip -> at_import = target_to_host (diep, nbytes, GET_UNSIGNED,
-                                            objfile);
-         break;
        case AT_location:
          dip -> at_location = diep;
          break;
@@ -3182,15 +3727,21 @@ completedieinfo (dip, objfile)
          dip -> at_name = diep;
          break;
        case AT_comp_dir:
-         dip -> at_comp_dir = diep;
+         /* For now, ignore any "hostname:" portion, since gdb doesn't
+            know how to deal with it.  (FIXME). */
+         dip -> at_comp_dir = strrchr (diep, ':');
+         if (dip -> at_comp_dir != NULL)
+           {
+             dip -> at_comp_dir++;
+           }
+         else
+           {
+             dip -> at_comp_dir = diep;
+           }
          break;
        case AT_producer:
          dip -> at_producer = diep;
          break;
-       case AT_frame_base:
-         dip -> at_frame_base = target_to_host (diep, nbytes, GET_UNSIGNED,
-                                                objfile);
-         break;
        case AT_start_scope:
          dip -> at_start_scope = target_to_host (diep, nbytes, GET_UNSIGNED,
                                                  objfile);
@@ -3240,8 +3791,7 @@ completedieinfo (dip, objfile)
          diep += strlen (diep) + 1;
          break;
        default:
-         SQUAWK (("unknown attribute form (0x%x)", form));
-         SQUAWK (("unknown attribute length, skipped remaining attributes"));;
+         complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form);
          diep = end;
          break;
        }
@@ -3273,16 +3823,18 @@ NOTES
        use it as signed data, then we need to explicitly sign extend the
        result until the bfd library is able to do this for us.
 
+       FIXME: Would a 32 bit target ever need an 8 byte result?
+
  */
 
-static unsigned long
+static CORE_ADDR
 target_to_host (from, nbytes, signextend, objfile)
      char *from;
      int nbytes;
      int signextend;           /* FIXME:  Unused */
      struct objfile *objfile;
 {
-  unsigned long rtnval;
+  CORE_ADDR rtnval;
 
   switch (nbytes)
     {
@@ -3299,7 +3851,7 @@ target_to_host (from, nbytes, signextend, objfile)
        rtnval = bfd_get_8 (objfile -> obfd, (bfd_byte *) from);
        break;
       default:
-       dwarfwarn ("no bfd support for %d byte data object", nbytes);
+       complain (&no_bfd_get_N, DIE_ID, DIE_NAME, nbytes);
        rtnval = 0;
        break;
     }
@@ -3355,7 +3907,7 @@ attribute_size (attr)
        nbytes = TARGET_FT_POINTER_SIZE (objfile);
        break;
       default:
-       SQUAWK (("unknown attribute form (0x%x)", form));
+       complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form);
        nbytes = -1;
        break;
       }