* dwarf2read.c: New file, DWARF 2 reader originally contributed by
authorStan Shebs <shebs@codesourcery.com>
Fri, 19 Jul 1996 21:16:13 +0000 (21:16 +0000)
committerStan Shebs <shebs@codesourcery.com>
Fri, 19 Jul 1996 21:16:13 +0000 (21:16 +0000)
Brent Benson, with additions by Gary Funck and Jerry Kreuscher.
* Makefile.in (COMMON_OBS): Add dwarf2read.o.
(SFILES): Add dwarf2read.c.
(dwarf2read.o): Add build rule.
* symfile.h (dwarf2_has_info, dwarf2_build_psymtabs): Declare
exported functions.
* elfread.c (elf_symfile_read): Call them.
(elf_symtab_read) [HARRIS_TARGET]: Skip some special symbols.

gdb/ChangeLog
gdb/Makefile.in
gdb/dwarf2read.c [new file with mode: 0644]
gdb/elfread.c
gdb/symfile.h

index 22ce466..d0fabde 100644 (file)
@@ -1,3 +1,15 @@
+Fri Jul 19 14:05:57 1996  Stan Shebs  <shebs@andros.cygnus.com>
+
+       * dwarf2read.c: New file, DWARF 2 reader originally contributed by
+       Brent Benson, with additions by Gary Funck and Jerry Kreuscher.
+       * Makefile.in (COMMON_OBS): Add dwarf2read.o.
+       (SFILES): Add dwarf2read.c.
+       (dwarf2read.o): Add build rule.
+       * symfile.h (dwarf2_has_info, dwarf2_build_psymtabs): Declare
+       exported functions.
+       * elfread.c (elf_symfile_read): Call them.
+       (elf_symtab_read) [HARRIS_TARGET]: Skip some special symbols.
+
 Thu Jul 18 01:22:01 1996  Geoffrey Noer  <noer@cygnus.com>
 
        * symfile.c (symfile_bfd_open): 
index 4144406..59946e7 100644 (file)
@@ -352,7 +352,8 @@ TARGET_FLAGS_TO_PASS = \
 SFILES = bcache.c blockframe.c breakpoint.c buildsym.c callback.c c-exp.y \
        c-lang.c c-typeprint.c c-valprint.c ch-exp.c ch-lang.c \
        ch-typeprint.c ch-valprint.c coffread.c command.c complaints.c \
-       corefile.c cp-valprint.c dbxread.c demangle.c dwarfread.c \
+       corefile.c cp-valprint.c \
+       dbxread.c demangle.c dwarfread.c dwarf2read.c \
        elfread.c environ.c eval.c expprint.c \
        f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c \
        gdbtypes.c infcmd.c inflow.c infrun.c language.c \
@@ -361,8 +362,9 @@ SFILES = bcache.c blockframe.c breakpoint.c buildsym.c callback.c c-exp.y \
        printcmd.c remote.c remote-nrom.c scm-exp.c scm-lang.c scm-valprint.c \
        source.c stabsread.c stack.c symfile.c symmisc.c \
        symtab.c target.c thread.c top.c \
-       typeprint.c utils.c valarith.c valops.c \
-       valprint.c values.c serial.c ser-unix.c mdebugread.c os9kread.c
+       typeprint.c utils.c \
+       valarith.c valops.c valprint.c values.c \
+       serial.c ser-unix.c mdebugread.c os9kread.c
 
 LINTFILES = $(SFILES) $(YYFILES) init.c
 
@@ -467,7 +469,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o stack.o thread.o \
        mem-break.o target.o parse.o language.o $(YYOBJ) buildsym.o \
        exec.o bcache.o objfiles.o minsyms.o maint.o demangle.o \
        dbxread.o coffread.o elfread.o \
-       dwarfread.o mipsread.o stabsread.o corefile.o \
+       dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
        c-lang.o ch-exp.o ch-lang.o f-lang.o m2-lang.o \
        scm-exp.o scm-lang.o scm-valprint.o complaints.o typeprint.o \
        c-typeprint.o ch-typeprint.o f-typeprint.o m2-typeprint.o \
@@ -1109,6 +1111,10 @@ dwarfread.o: dwarfread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \
        $(expression_h) $(gdbtypes_h) language.h objfiles.h symfile.h \
        $(symtab_h) gdb_string.h
 
+dwarf2read.o: dwarf2read.c $(bfd_h) buildsym.h $(defs_h) \
+       $(expression_h) $(gdbtypes_h) language.h objfiles.h symfile.h \
+       $(symtab_h) gdb_string.h
+
 elfread.o: elfread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \
        gdb-stabs.h objfiles.h symfile.h $(symtab_h) gdb_string.h
 
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
new file mode 100644 (file)
index 0000000..7e7891d
--- /dev/null
@@ -0,0 +1,4402 @@
+/* DWARF 2 debugging format support for GDB.
+   Copyright 1994, 1995, 1996 Free Software Foundation, Inc.
+
+   Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology,
+   Inc.  with support from Florida State University (under contract
+   with the Ada Joint Program Office), and Silicon Graphics, Inc.
+   Initial contribution by Brent Benson, Harris Computer Systems, Inc.,
+   based on Fred Fish's (Cygnus Support) implementation of DWARF 1
+   support in dwarfread.c
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "bfd.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "elf/dwarf2.h"
+#include "buildsym.h"
+#include "demangle.h"
+#include "expression.h"
+#include "language.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+
+#ifndef        NO_SYS_FILE
+#include <sys/file.h>
+#endif
+
+/* .debug_info header for a compilation unit 
+   Because of alignment constraints, this structure has padding and cannot
+   be mapped directly onto the beginning of the .debug_info section.  */
+typedef struct comp_unit_header
+  {
+    unsigned int length;       /* length of the .debug_info
+                                  contribution */
+    unsigned short version;    /* version number -- 2 for DWARF
+                                  version 2 */
+    unsigned int abbrev_offset;        /* offset into .debug_abbrev section */
+    unsigned char addr_size;   /* byte size of an address -- 4 */
+  }
+_COMP_UNIT_HEADER;
+#define _ACTUAL_COMP_UNIT_HEADER_SIZE 11
+
+/* .debug_pubnames header
+   Because of alignment constraints, this structure has padding and cannot
+   be mapped directly onto the beginning of the .debug_info section.  */
+typedef struct pubnames_header
+  {
+    unsigned int length;       /* length of the .debug_pubnames
+                                  contribution  */
+    unsigned char version;     /* version number -- 2 for DWARF
+                                  version 2 */
+    unsigned int info_offset;  /* offset into .debug_info section */
+    unsigned int info_size;    /* byte size of .debug_info section
+                                  portion */
+  }
+_PUBNAMES_HEADER;
+#define _ACTUAL_PUBNAMES_HEADER_SIZE 13
+
+/* .debug_pubnames header
+   Because of alignment constraints, this structure has padding and cannot
+   be mapped directly onto the beginning of the .debug_info section.  */
+typedef struct aranges_header
+  {
+    unsigned int length;       /* byte len of the .debug_aranges
+                                  contribution */
+    unsigned short version;    /* version number -- 2 for DWARF
+                                  version 2 */
+    unsigned int info_offset;  /* offset into .debug_info section */
+    unsigned char addr_size;   /* byte size of an address */
+    unsigned char seg_size;    /* byte size of segment descriptor */
+  }
+_ARANGES_HEADER;
+#define _ACTUAL_ARANGES_HEADER_SIZE 12
+
+/* .debug_line statement program prologue
+   Because of alignment constraints, this structure has padding and cannot
+   be mapped directly onto the beginning of the .debug_info section.  */
+typedef struct statement_prologue
+  {
+    unsigned int total_length; /* byte length of the statement
+                                  information */
+    unsigned short version;    /* version number -- 2 for DWARF
+                                  version 2 */
+    unsigned int prologue_length;      /* # bytes between prologue &
+                                          stmt program */
+    unsigned char minimum_instruction_length;  /* byte size of
+                                                  smallest instr */
+    unsigned char default_is_stmt;     /* initial value of is_stmt
+                                          register */
+    char line_base;
+    unsigned char line_range;
+    unsigned char opcode_base; /* number assigned to first special
+                                  opcode */
+    unsigned char *standard_opcode_lengths;
+  }
+_STATEMENT_PROLOGUE;
+
+/* offsets and sizes of debugging sections */
+
+static file_ptr dwarf_info_offset;
+static file_ptr dwarf_abbrev_offset;
+static file_ptr dwarf_line_offset;
+static file_ptr dwarf_pubnames_offset;
+static file_ptr dwarf_aranges_offset;
+static file_ptr dwarf_loc_offset;
+static file_ptr dwarf_macinfo_offset;
+static file_ptr dwarf_str_offset;
+
+static unsigned int dwarf_info_size;
+static unsigned int dwarf_abbrev_size;
+static unsigned int dwarf_line_size;
+static unsigned int dwarf_pubnames_size;
+static unsigned int dwarf_aranges_size;
+static unsigned int dwarf_loc_size;
+static unsigned int dwarf_macinfo_size;
+static unsigned int dwarf_str_size;
+
+/* names of the debugging sections */
+
+#define INFO_SECTION     ".debug_info"
+#define ABBREV_SECTION   ".debug_abbrev"
+#define LINE_SECTION     ".debug_line"
+#define PUBNAMES_SECTION ".debug_pubnames"
+#define ARANGES_SECTION  ".debug_aranges"
+#define LOC_SECTION      ".debug_loc"
+#define MACINFO_SECTION  ".debug_macinfo"
+#define STR_SECTION      ".debug_str"
+
+/* Get at parts of an attribute structure */
+
+#define DW_STRING(attr)    ((attr)->u.str)
+#define DW_UNSND(attr)     ((attr)->u.unsnd)
+#define DW_BLOCK(attr)     ((attr)->u.blk)
+#define DW_SND(attr)       ((attr)->u.snd)
+#define DW_ADDR(attr)     ((attr)->u.addr)
+
+/* local data types */
+
+/* The data in a compilation unit header looks like this.  */
+struct comp_unit_head
+  {
+    int length;
+    short version;
+    int abbrev_offset;
+    unsigned char addr_size;
+  };
+
+/* The data in the .debug_line statement prologue looks like this.  */
+struct line_head
+  {
+    unsigned int total_length;
+    unsigned short version;
+    unsigned int prologue_length;
+    unsigned char minimum_instruction_length;
+    unsigned char default_is_stmt;
+    char line_base;
+    unsigned char line_range;
+    unsigned char opcode_base;
+    unsigned char *standard_opcode_lengths;
+  };
+
+/* When we construct a partial symbol table entry we only
+   need this much information. */
+struct partial_die_info
+  {
+    unsigned short tag;
+    unsigned char has_children;
+    unsigned char is_external;
+    unsigned int offset;
+    unsigned int abbrev;
+    char *name;
+    CORE_ADDR lowpc;
+    CORE_ADDR highpc;
+    struct dwarf_block *locdesc;
+    unsigned int language;
+    int value;
+  };
+
+/* This data structure holds the information of an abbrev. */
+struct abbrev_info
+  {
+    unsigned int number;       /* number identifying abbrev */
+    unsigned int tag;          /* dwarf tag */
+    int has_children;          /* boolean */
+    unsigned int num_attrs;    /* number of attributes */
+    struct attr_abbrev *attrs; /* an array of attribute descriptions */
+    struct abbrev_info *next;  /* next in chain */
+  };
+
+struct attr_abbrev
+  {
+    unsigned int name;
+    unsigned int form;
+  };
+
+/* This data structure holds a complete die structure. */
+struct die_info
+  {
+    unsigned short tag;                 /* Tag indicating type of die */
+    unsigned short has_children; /* Does the die have children */
+    unsigned int abbrev;        /* Abbrev number */
+    unsigned int offset;        /* Offset in .debug_info section */
+    unsigned int num_attrs;     /* Number of attributes */
+    struct attribute *attrs;    /* An array of attributes */
+    struct die_info *next_ref;  /* Next die in ref hash table */
+    struct die_info *next;      /* Next die in linked list */
+    struct type *type;          /* Cached type information */
+  };
+
+/* Attributes have a name and a value */
+struct attribute
+  {
+    unsigned short name;
+    unsigned short form;
+    union
+      {
+       char *str;
+       struct dwarf_block *blk;
+       unsigned int unsnd;
+       int snd;
+       CORE_ADDR addr;
+      }
+    u;
+  };
+
+/* Blocks are a bunch of untyped bytes. */
+struct dwarf_block
+  {
+    unsigned int size;
+    char *data;
+  };
+
+/* We only hold one compilation unit's abbrevs in
+   memory at any one time.  */
+#ifndef ABBREV_HASH_SIZE
+#define ABBREV_HASH_SIZE 121
+#endif
+#ifndef ATTR_ALLOC_CHUNK
+#define ATTR_ALLOC_CHUNK 4
+#endif
+
+/* FIXME: do away with this */
+
+#ifndef DWARF2_MAX_STRING_SIZE
+#define DWARF2_MAX_STRING_SIZE 1024
+#endif
+
+static struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
+
+/* A hash table of die offsets for following references.  */
+#ifndef REF_HASH_SIZE
+#define REF_HASH_SIZE 1021
+#endif
+
+static struct die_info *die_ref_table[REF_HASH_SIZE];
+
+/* Allocate fields for structs, unions and enums in this size.  */
+#ifndef DW_FIELD_ALLOC_CHUNK
+#define DW_FIELD_ALLOC_CHUNK 4
+#endif
+
+/* The language we are debugging.  */
+static enum language cu_language;
+static const struct language_defn *cu_language_defn;
+
+/* Actually data from the sections.  */
+static char *dwarf_info_buffer;
+static char *dwarf_abbrev_buffer;
+static char *dwarf_line_buffer;
+
+/* A zeroed version of several structures for initialization purposes.  */
+static struct partial_die_info zeroed_partial_die;
+static struct die_info zeroed_die;
+
+/* The generic symbol table building routines have separate lists for
+   file scope symbols and all all other scopes (local scopes).  So
+   we need to select the right one to pass to add_symbol_to_list().
+   We do it by keeping a pointer to the correct list in list_in_scope.
+
+   FIXME:  The original dwarf code just treated the file scope as the first
+   local scope, and all other local scopes as nested local scopes, and worked
+   fine.  Check to see if we really need to distinguish these
+   in buildsym.c.  */
+static struct pending **list_in_scope = &file_symbols;
+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 */
+
+/* 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 */
+
+/* FIXME - set from bfd function */
+static int bits_per_byte = 8;
+
+/* Keep track of whether we have given a warning about not
+   handling DW_TAG_const_type dies.  */
+static int tag_const_warning_given = 0;
+
+/* Keep track of whether we have given a warning about not
+   handling DW_TAG_volatile_type dies.  */
+static int tag_volatile_warning_given = 0;
+
+/* Keep track of constant array bound warning.  */
+static int array_bound_warning_given = 0;
+
+/* Remember the addr_size read from the dwarf.
+   If a target expects to link compilation units with differing address
+   sizes, gdb needs to be sure that the appropriate size is here for
+   whatever scope is currently getting read. */
+static int address_size;
+
+/* Externals references.  */
+extern int info_verbose;       /* From main.c; nonzero => verbose */
+
+/* local function prototypes */
+
+static void dwarf2_locate_sections PARAMS ((bfd *, asection *, PTR));
+
+static void dwarf2_build_psymtabs_easy PARAMS ((struct objfile *,
+                                               struct section_offsets *,
+                                               int));
+static void dwarf2_build_psymtabs_hard PARAMS ((struct objfile *,
+                                               struct section_offsets *,
+                                               int));
+
+static char *scan_partial_symbols PARAMS ((char *, struct objfile *,
+                                          CORE_ADDR *, CORE_ADDR *));
+
+static void add_partial_symbol PARAMS ((struct partial_die_info *,
+                                       struct objfile *));
+
+static void dwarf2_psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+static void psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
+
+static void add_die_to_symtab PARAMS ((struct die_info *, struct objfile *));
+
+static char *dwarf2_read_section PARAMS ((bfd *, file_ptr, unsigned int));
+
+static void dwarf2_read_abbrevs PARAMS ((bfd *, unsigned int));
+
+static void dwarf2_empty_abbrev_table PARAMS ((void));
+
+static struct abbrev_info *dwarf2_lookup_abbrev PARAMS ((unsigned int));
+
+static char *read_partial_die PARAMS ((struct partial_die_info *,
+                                      bfd *, char *, int *));
+
+static char *read_full_die PARAMS ((struct die_info **, bfd *, char *));
+
+static unsigned int read_1_byte PARAMS ((bfd *, char *));
+
+static unsigned int read_2_bytes PARAMS ((bfd *, char *));
+
+static unsigned int read_4_bytes PARAMS ((bfd *, char *));
+
+static unsigned int read_8_bytes PARAMS ((bfd *, char *));
+
+static CORE_ADDR read_address PARAMS ((bfd *, char *));
+
+static char *read_n_bytes PARAMS ((bfd *, char *, unsigned int));
+
+static char *read_string PARAMS ((bfd *, char *, unsigned int *));
+
+static unsigned int read_unsigned_leb128 PARAMS ((bfd *, char *,
+                                                 unsigned int *));
+
+static int read_signed_leb128 PARAMS ((bfd *, char *, unsigned int *));
+
+static void set_cu_language PARAMS ((unsigned int));
+
+static void record_minimal_symbol PARAMS ((char *, CORE_ADDR,
+                                          enum minimal_symbol_type,
+                                          struct objfile *));
+
+static int convert_locdesc PARAMS ((struct dwarf_block *));
+
+static struct attribute *dwarf_attr PARAMS ((struct die_info *,
+                                            unsigned int));
+
+static void dwarf_decode_lines PARAMS ((unsigned int, bfd *));
+
+static struct symbol *new_symbol PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static struct type *die_type PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static struct type *type_at_offset PARAMS ((unsigned int offset, struct objfile * objfile));
+
+static struct type *tag_type_to_type PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static void read_type_die PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static void read_typedef PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static void read_base_type PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static void read_file_scope PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static void read_func_scope PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static void read_lexical_block_scope PARAMS ((struct die_info * die,
+                                             struct objfile * objfile));
+
+static void read_structure_scope PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static void read_common_block PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static void read_enumeration PARAMS ((struct die_info * die, struct objfile * objfile));
+
+static struct type * dwarf_base_type PARAMS ((int encoding, int size));
+
+static CORE_ADDR decode_locdesc PARAMS ((struct dwarf_block *,
+                                        struct objfile *));
+
+static char *create_name PARAMS ((char *, struct obstack *));
+
+static void dwarf_read_array_type PARAMS ((struct die_info * die,
+                                          struct objfile * objfile));
+
+static void read_tag_pointer_type PARAMS ((struct die_info * die,
+                                          struct objfile * objfile));
+
+static void read_tag_const_type PARAMS ((struct die_info * die,
+                                        struct objfile * objfile));
+
+static void read_tag_volatile_type PARAMS ((struct die_info * die,
+                                           struct objfile * objfile));
+
+static void read_tag_string_type PARAMS ((struct die_info * die,
+                                         struct objfile * objfile));
+
+static void read_subroutine_type PARAMS ((struct die_info * die,
+                                         struct objfile * objfile));
+
+struct die_info *read_comp_unit PARAMS ((char *info_ptr, bfd * abfd));
+
+static void free_die_list PARAMS ((struct die_info * dies));
+
+static void process_die PARAMS ((struct die_info *, struct objfile *));
+
+static char *dwarf_tag_name PARAMS ((unsigned tag));
+
+static char *dwarf_attr_name PARAMS ((unsigned attr));
+
+static char *dwarf_form_name PARAMS ((unsigned form));
+
+static char *dwarf_stack_op_name PARAMS ((unsigned op));
+
+static char *dwarf_bool_name PARAMS ((unsigned bool));
+
+static char *dwarf_bool_name PARAMS ((unsigned tag));
+
+static char *dwarf_type_encoding_name PARAMS ((unsigned enc));
+
+static char *dwarf_cfi_name PARAMS ((unsigned cfi_opc));
+
+struct die_info *copy_die PARAMS ((struct die_info *old_die));
+
+struct die_info *sibling_die PARAMS ((struct die_info *die));
+
+void dump_die PARAMS ((struct die_info *die));
+
+void dump_die_list PARAMS ((struct die_info *dies));
+
+void store_in_ref_table PARAMS ((unsigned int, struct die_info *));
+
+struct die_info *follow_die_ref PARAMS ((unsigned int offset));
+
+static struct type *dwarf2_fundamental_type PARAMS ((struct objfile *, int));
+
+/* memory allocation interface */
+
+static struct type *dwarf_alloc_type PARAMS ((struct objfile *));
+
+static struct abbrev_info *dwarf_alloc_abbrev PARAMS ((void));
+
+static struct dwarf_block *dwarf_alloc_block PARAMS ((void));
+
+static struct die_info *dwarf_alloc_die PARAMS ((void));
+
+/* Try to locate the sections we need for DWARF 2 debugging
+   information and return true if we have enough to do something.  */
+
+int
+dwarf2_has_info (abfd)
+     bfd *abfd;
+{
+  dwarf_info_offset = dwarf_abbrev_offset = dwarf_line_offset = 0;
+  bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
+  if (dwarf_info_offset && dwarf_abbrev_offset && dwarf_line_offset)
+    {
+      return 1;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+/* This function is mapped across the sections and remembers the
+   offset and size of each of the debugging sections we are interested
+   in.  */
+
+static void
+dwarf2_locate_sections (ignore_abfd, sectp, ignore_ptr)
+     bfd *ignore_abfd;
+     asection *sectp;
+     PTR ignore_ptr;
+{
+  if (STREQ (sectp->name, INFO_SECTION))
+    {
+      dwarf_info_offset = sectp->filepos;
+      dwarf_info_size = bfd_get_section_size_before_reloc (sectp);
+    }
+  else if (STREQ (sectp->name, ABBREV_SECTION))
+    {
+      dwarf_abbrev_offset = sectp->filepos;
+      dwarf_abbrev_size = bfd_get_section_size_before_reloc (sectp);
+    }
+  else if (STREQ (sectp->name, LINE_SECTION))
+    {
+      dwarf_line_offset = sectp->filepos;
+      dwarf_line_size = bfd_get_section_size_before_reloc (sectp);
+    }
+  else if (STREQ (sectp->name, PUBNAMES_SECTION))
+    {
+      dwarf_pubnames_offset = sectp->filepos;
+      dwarf_pubnames_size = bfd_get_section_size_before_reloc (sectp);
+    }
+  else if (STREQ (sectp->name, ARANGES_SECTION))
+    {
+      dwarf_aranges_offset = sectp->filepos;
+      dwarf_aranges_size = bfd_get_section_size_before_reloc (sectp);
+    }
+  else if (STREQ (sectp->name, LOC_SECTION))
+    {
+      dwarf_loc_offset = sectp->filepos;
+      dwarf_loc_size = bfd_get_section_size_before_reloc (sectp);
+    }
+  else if (STREQ (sectp->name, MACINFO_SECTION))
+    {
+      dwarf_macinfo_offset = sectp->filepos;
+      dwarf_macinfo_size = bfd_get_section_size_before_reloc (sectp);
+    }
+  else if (STREQ (sectp->name, STR_SECTION))
+    {
+      dwarf_str_offset = sectp->filepos;
+      dwarf_str_size = bfd_get_section_size_before_reloc (sectp);
+    }
+}
+
+/* Build a partial symbol table.  */
+
+void
+dwarf2_build_psymtabs (objfile, section_offsets, mainline)
+    struct objfile *objfile;
+    struct section_offsets *section_offsets;
+    int mainline;
+{
+  bfd *abfd = objfile->obfd;
+
+  /* We definitely need the .debug_info, .debug_abbrev, and .debug_line
+     sections */
+
+  dwarf_info_buffer = dwarf2_read_section (abfd,
+                                          dwarf_info_offset,
+                                          dwarf_info_size);
+  dwarf_abbrev_buffer = dwarf2_read_section (abfd,
+                                            dwarf_abbrev_offset,
+                                            dwarf_abbrev_size);
+  dwarf_line_buffer = dwarf2_read_section (abfd,
+                                          dwarf_line_offset,
+                                          dwarf_line_size);
+
+  if (mainline || objfile->global_psymbols.size == 0 ||
+      objfile->static_psymbols.size == 0)
+    {
+      init_psymbol_list (objfile, 1024);
+    }
+
+#if 0
+  if (dwarf_aranges_offset && dwarf_pubnames_offset)
+    {
+      /* Things are significanlty easier if we have .debug_aranges and
+         .debug_pubnames sections */
+
+      dwarf2_build_psymtabs_easy (objfile, section_offsets, mainline);
+    }
+  else
+#endif
+    /* only test this case for now */
+    {          
+      /* In this case we have to work a bit harder */
+      dwarf2_build_psymtabs_hard (objfile, section_offsets, mainline);
+    }
+}
+
+/* Build the partial symbol table from the information in the
+   .debug_pubnames and .debug_aranges sections.  */
+
+static void
+dwarf2_build_psymtabs_easy (objfile, section_offsets, mainline)
+     struct objfile *objfile;
+     struct section_offsets *section_offsets;
+     int mainline;
+{
+  bfd *abfd = objfile->obfd;
+  char *aranges_buffer, *pubnames_buffer;
+  char *aranges_ptr, *pubnames_ptr;
+  unsigned int entry_length, version, info_offset, info_size;
+
+  pubnames_buffer = dwarf2_read_section (abfd,
+                                        dwarf_pubnames_offset,
+                                        dwarf_pubnames_size);
+  pubnames_ptr = pubnames_buffer;
+  while ((pubnames_ptr - pubnames_buffer) < dwarf_pubnames_size)
+    {
+      entry_length = read_4_bytes (abfd, pubnames_ptr);
+      pubnames_ptr += 4;
+      version = read_1_byte (abfd, pubnames_ptr);
+      pubnames_ptr += 1;
+      info_offset = read_4_bytes (abfd, pubnames_ptr);
+      pubnames_ptr += 4;
+      info_size = read_4_bytes (abfd, pubnames_ptr);
+      pubnames_ptr += 4;
+    }
+
+  aranges_buffer = dwarf2_read_section (abfd,
+                                       dwarf_aranges_offset,
+                                       dwarf_aranges_size);
+
+}
+
+/* Build the partial symbol table by doing a quick pass through the
+   .debug_info and .debug_abbrev sections.  */
+
+static void
+dwarf2_build_psymtabs_hard (objfile, section_offsets, mainline)
+     struct objfile *objfile;
+     struct section_offsets *section_offsets;
+     int mainline;
+{
+  /* Instead of reading this into a big buffer, we should probably use
+     mmap()  on architectures that support it. (FIXME) */
+  bfd *abfd = objfile->obfd;
+  char *info_ptr, *abbrev_ptr;
+  char *beg_of_comp_unit, *comp_unit_die_offset;
+  struct comp_unit_head cu_header;
+  struct partial_die_info comp_unit_die;
+  struct partial_symtab *pst;
+  struct cleanup *back_to;
+  int comp_unit_has_pc_info;
+  int has_pc_info;
+  CORE_ADDR lowpc, highpc;
+
+  comp_unit_die = zeroed_partial_die;
+  info_ptr = dwarf_info_buffer;
+  abbrev_ptr = dwarf_abbrev_buffer;
+
+  while ((info_ptr - dwarf_info_buffer)
+         + ((info_ptr - dwarf_info_buffer) % 4) < dwarf_info_size)
+    {
+      beg_of_comp_unit = info_ptr;
+      cu_header.length = read_4_bytes (abfd, info_ptr);
+      info_ptr += 4;
+      cu_header.version = read_2_bytes (abfd, info_ptr);
+      info_ptr += 2;
+      cu_header.abbrev_offset = read_4_bytes (abfd, info_ptr);
+      info_ptr += 4;
+      cu_header.addr_size = read_1_byte (abfd, info_ptr);
+      info_ptr += 1;
+      address_size = cu_header.addr_size;
+
+      if (cu_header.version != 2)
+       {
+         error ("Dwarf Error: wrong version in compilation unit header.");
+         return;
+       }
+
+      /* Read the abbrevs for this compilation unit into a table */
+      dwarf2_read_abbrevs (abfd, cu_header.abbrev_offset);
+      back_to = make_cleanup (dwarf2_empty_abbrev_table, NULL);
+
+      /* Read the compilation unit die */
+      info_ptr = read_partial_die (&comp_unit_die, abfd,
+                                  info_ptr, &comp_unit_has_pc_info);
+
+      /* Set the language we're debugging */
+      set_cu_language (comp_unit_die.language);
+
+      /* Allocate a new partial symbol table structure */
+      pst = start_psymtab_common (objfile, section_offsets,
+                                 comp_unit_die.name,
+                                 comp_unit_die.lowpc,
+                                 objfile->global_psymbols.next,
+                                 objfile->static_psymbols.next);
+
+      /* Store offset in the .debug_info section of the comp_unit_die.  */
+      pst->read_symtab_private = (char *)
+                                (beg_of_comp_unit - dwarf_info_buffer);
+
+      /* Store the function that reads in the rest of the symbol table */
+      pst->read_symtab = dwarf2_psymtab_to_symtab;
+
+      /* Read the rest of the partial symbols from this comp unit */
+      info_ptr = scan_partial_symbols (info_ptr, objfile, &lowpc, &highpc);
+
+      /* If the compilation unit didn't have an explicit address range,
+        then use the information extracted from its child dies.  */
+      if (!comp_unit_has_pc_info)
+       {
+         comp_unit_die.lowpc  = lowpc;
+         comp_unit_die.highpc = highpc;
+        }
+      pst->textlow  = comp_unit_die.lowpc;
+      pst->texthigh = comp_unit_die.highpc;
+
+      pst->n_global_syms = objfile->global_psymbols.next -
+       (objfile->global_psymbols.list + pst->globals_offset);
+      pst->n_static_syms = objfile->static_psymbols.next -
+       (objfile->static_psymbols.list + pst->statics_offset);
+      sort_pst_symbols (pst);
+
+      /* If there is already a psymtab or symtab for a file of this
+         name, remove it. (If there is a symtab, more drastic things
+         also happen.) This happens in VxWorks.  */
+      free_named_symtabs (pst->filename);
+
+      info_ptr = beg_of_comp_unit + cu_header.length + 4;
+    }
+  do_cleanups (back_to);
+}
+
+/* Read in all interesting dies to the end of the compilation unit.  */
+
+static char *
+scan_partial_symbols (info_ptr, objfile, lowpc, highpc)
+     char *info_ptr;
+     struct objfile *objfile;
+     CORE_ADDR *lowpc;
+     CORE_ADDR *highpc;
+{
+  /* FIXME: This should free the attributes of the partial die structure
+     when it is done with them (is there a more efficient way
+     to do this). */
+  bfd *abfd = objfile->obfd;
+  struct partial_die_info pdi;
+  int nesting_level = 1;       /* we've already read in comp_unit_die */
+  int has_pc_info;
+
+  pdi = zeroed_partial_die;
+  *lowpc  = ((CORE_ADDR) -1);
+  *highpc = ((CORE_ADDR) 0);
+  do
+    {
+      info_ptr = read_partial_die (&pdi, abfd, info_ptr, &has_pc_info);
+      switch (pdi.tag)
+       {
+       case DW_TAG_subprogram:
+       case DW_TAG_variable:
+       case DW_TAG_typedef:
+       case DW_TAG_class_type:
+       case DW_TAG_structure_type:
+       case DW_TAG_union_type:
+         if (pdi.is_external || nesting_level == 1)
+           {
+             if (pdi.name)
+               {
+                 add_partial_symbol (&pdi, objfile);
+               }
+           }
+          if (has_pc_info)
+            {
+              if (pdi.lowpc < *lowpc)
+                {
+                  *lowpc = pdi.lowpc;
+                }
+              if (pdi.highpc > *lowpc)
+                {
+                  *highpc = pdi.highpc;
+                }
+            }
+       }
+      if (pdi.has_children)
+       {
+         nesting_level++;
+       }
+      if (pdi.tag == 0)
+       {
+         nesting_level--;
+       }
+    }
+  while (nesting_level);
+  return info_ptr;
+}
+
+static void
+add_partial_symbol (pdi, objfile)
+     struct partial_die_info *pdi;
+     struct objfile *objfile;
+{
+  switch (pdi->tag)
+    {
+    case DW_TAG_subprogram:
+      if (pdi->is_external)
+       {
+         record_minimal_symbol (pdi->name, pdi->lowpc,
+                                mst_text, objfile);
+         add_psymbol_to_list (pdi->name, strlen (pdi->name),
+                              VAR_NAMESPACE, LOC_BLOCK,
+                              &objfile->global_psymbols,
+                              0, pdi->lowpc, cu_language, objfile);
+       }
+      else
+       {
+         add_psymbol_to_list (pdi->name, strlen (pdi->name),
+                              VAR_NAMESPACE, LOC_BLOCK,
+                              &objfile->static_psymbols,
+                              0, pdi->lowpc, cu_language, objfile);
+       }
+      break;
+    case DW_TAG_variable:
+      if (pdi->is_external)
+       {
+         record_minimal_symbol (pdi->name, convert_locdesc (pdi->locdesc),
+                                mst_data, objfile);
+         add_psymbol_to_list (pdi->name, strlen (pdi->name),
+                              VAR_NAMESPACE, LOC_STATIC,
+                              &objfile->global_psymbols,
+                              0, 0, cu_language, objfile);
+       }
+      else
+       {
+         add_psymbol_to_list (pdi->name, strlen (pdi->name),
+                              VAR_NAMESPACE, LOC_STATIC,
+                              &objfile->static_psymbols,
+                              0, 0, cu_language, objfile);
+       }
+      break;
+    case DW_TAG_typedef:
+      add_psymbol_to_list (pdi->name, strlen (pdi->name),
+                          VAR_NAMESPACE, LOC_TYPEDEF,
+                          &objfile->static_psymbols,
+                          0, 0, cu_language, objfile);
+      break;
+    case DW_TAG_class_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_union_type:
+    case DW_TAG_enumeration_type:
+      add_psymbol_to_list (pdi->name, strlen (pdi->name),
+                          STRUCT_NAMESPACE, LOC_TYPEDEF,
+                          &objfile->static_psymbols,
+                          0, 0, cu_language, objfile);
+      if (cu_language == language_cplus)
+       {
+         /* For C++, these implicitly act as typedefs as well. */
+         add_psymbol_to_list (pdi->name, strlen (pdi->name),
+                              VAR_NAMESPACE, LOC_TYPEDEF,
+                              &objfile->static_psymbols,
+                              0, 0, cu_language, objfile);
+       }
+      break;
+    }
+}
+
+/* Expand this partial symbol table into a full symbol table.  */
+
+static void
+dwarf2_psymtab_to_symtab (pst)
+     struct partial_symtab *pst;
+{
+  /* FIXME: This is barely more than a stub.  */
+  if (pst != NULL)
+    {
+      if (pst->readin)
+       {
+         warning ("bug: psymtab for %s is already read in.", pst->filename);
+       }
+      else
+       {
+         psymtab_to_symtab_1 (pst);
+       }
+    }
+}
+
+static void
+psymtab_to_symtab_1 (pst)
+     struct partial_symtab *pst;
+{
+  struct objfile *objfile = pst->objfile;
+  bfd *abfd = objfile->obfd;
+  struct comp_unit_head cu_header;
+  struct die_info *dies;
+  struct attribute *attr;
+  unsigned long offset;
+  unsigned long int nesting_level;
+  CORE_ADDR highpc;
+  struct attribute *high_pc_attr;
+  struct die_info *child_die;
+  char *info_ptr;
+  struct context_stack *context;
+  struct symtab *symtab;
+  struct cleanup *abbrev_cleanup, *die_cleanup;
+
+  /* Get the offset of this compilation units debug info  */
+  offset = (unsigned long) pst->read_symtab_private;
+  info_ptr = dwarf_info_buffer + offset;
+
+  /* read in the comp_unit header  */
+  cu_header.length = read_4_bytes (abfd, info_ptr);
+  info_ptr += 4;
+  cu_header.version = read_2_bytes (abfd, info_ptr);
+  info_ptr += 2;
+  cu_header.abbrev_offset = read_4_bytes (abfd, info_ptr);
+  info_ptr += 4;
+  cu_header.addr_size = read_1_byte (abfd, info_ptr);
+  info_ptr += 1;
+
+  /* Read the abbrevs for this compilation unit  */
+  dwarf2_read_abbrevs (abfd, cu_header.abbrev_offset);
+  abbrev_cleanup = make_cleanup (dwarf2_empty_abbrev_table, NULL);
+
+  dies = read_comp_unit (info_ptr, abfd);
+
+  die_cleanup = make_cleanup (free_die_list, dies);
+
+  /* Do line number decoding in read_file_scope () */
+  process_die (dies, objfile);
+
+  attr = dwarf_attr (dies, DW_AT_high_pc);
+  if (attr)
+    {
+      highpc = DW_ADDR (attr);
+    }
+  else
+    {
+      /* Some compilers don't define a DW_AT_high_pc attribute for
+        the compilation unit.   If the DW_AT_high_pc is missing,
+        synthesize it, by scanning the DIE's below the compilation unit.  */
+      highpc = 0;
+      if (dies->has_children)
+       {
+         child_die = dies->next;
+         while (child_die && child_die->tag)
+           {
+             if (child_die->tag == DW_TAG_subprogram)
+               {
+                 high_pc_attr = dwarf_attr (child_die, DW_AT_high_pc);
+                 if (high_pc_attr)
+                   {
+                     highpc = max (highpc, DW_ADDR (high_pc_attr));
+                   }
+               }
+             child_die = sibling_die (child_die);
+           }
+       }
+    }
+
+  symtab = end_symtab (highpc, objfile, 0);
+  if (symtab != NULL)
+    {
+      symtab->language = cu_language;
+    }
+  pst->symtab = symtab;
+  pst->readin = 1;
+  if (info_verbose)
+    {
+      printf_filtered ("Sorting symbol table...");
+      wrap_here ("");
+      fflush (stdout);
+    }
+  sort_symtab_syms (pst->symtab);
+  do_cleanups (abbrev_cleanup);
+}
+
+/* Process a die and its children.  */
+
+static void
+process_die (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  switch (die->tag)
+    {
+    case DW_TAG_padding:
+      break;
+    case DW_TAG_compile_unit:
+      read_file_scope (die, objfile);
+      break;
+    case DW_TAG_subprogram:
+      if (dwarf_attr (die, DW_AT_low_pc))
+       {
+         read_func_scope (die, objfile);
+       }
+      break;
+    case DW_TAG_lexical_block:
+      read_lexical_block_scope (die, objfile);
+      break;
+    case DW_TAG_class_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_union_type:
+      read_structure_scope (die, objfile);
+      break;
+    case DW_TAG_enumeration_type:
+      read_enumeration (die, objfile);
+      break;
+    case DW_TAG_subroutine_type:
+      read_subroutine_type (die, objfile);
+      break;
+    case DW_TAG_array_type:
+      dwarf_read_array_type (die, objfile);
+      break;
+    case DW_TAG_pointer_type:
+      read_tag_pointer_type (die, objfile);
+      break;
+    case DW_TAG_string_type:
+      read_tag_string_type (die, objfile);
+      break;
+    case DW_TAG_base_type:
+      read_base_type (die, objfile);
+      break;
+    case DW_TAG_common_block:
+      read_common_block (die, objfile);
+      break;
+    case DW_TAG_common_inclusion:
+      break;
+    default:
+      new_symbol (die, objfile);
+      break;
+    }
+}
+
+static void
+read_file_scope (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  unsigned int line_offset = 0;
+  CORE_ADDR lowpc  = ((CORE_ADDR) -1);
+  CORE_ADDR highpc = ((CORE_ADDR) 0);
+  struct attribute *attr, *low_pc_attr, *high_pc_attr;
+  char *name = NULL;
+  char *comp_dir = NULL;
+  struct die_info *child_die;
+  bfd *abfd = objfile->obfd;
+
+  low_pc_attr = dwarf_attr (die, DW_AT_low_pc);
+  if (low_pc_attr)
+    {
+      lowpc = DW_ADDR (low_pc_attr);
+    }
+  high_pc_attr = dwarf_attr (die, DW_AT_high_pc);
+  if (high_pc_attr)
+    {
+      highpc = DW_ADDR (high_pc_attr);
+    }
+  if (!low_pc_attr || !high_pc_attr)
+    {
+      if (die->has_children)
+       {
+         child_die = die->next;
+         while (child_die && child_die->tag)
+           {
+             if (child_die->tag == DW_TAG_subprogram)
+               {
+                 low_pc_attr = dwarf_attr (child_die, DW_AT_low_pc);
+                 if (low_pc_attr)
+                   {
+                     lowpc = min (lowpc, DW_ADDR (low_pc_attr));
+                   }
+                 high_pc_attr = dwarf_attr (child_die, DW_AT_high_pc);
+                 if (high_pc_attr)
+                   {
+                     highpc = max (highpc, DW_ADDR (high_pc_attr));
+                   }
+               }
+             child_die = sibling_die (child_die);
+           }
+       }
+    }
+
+  attr = dwarf_attr (die, DW_AT_name);
+  if (attr)
+    {
+      name = DW_STRING (attr);
+    }
+  attr = dwarf_attr (die, DW_AT_comp_dir);
+  if (attr)
+    {
+      comp_dir = DW_STRING (attr);
+    }
+
+  if (objfile->ei.entry_point >= lowpc &&
+      objfile->ei.entry_point < highpc)
+    {
+      objfile->ei.entry_file_lowpc = lowpc;
+      objfile->ei.entry_file_highpc = highpc;
+    }
+
+  attr = dwarf_attr (die, DW_AT_language);
+  if (attr)
+    {
+      set_cu_language (DW_UNSND (attr));
+    }
+
+#if 0
+    /* FIXME:Do something here.  */
+    if (dip->at_producer != NULL)
+    {
+      handle_producer (dip->at_producer);
+    }
+#endif
+
+  start_symtab (name, comp_dir, lowpc);
+
+  /* Decode line number information.  */
+  attr = dwarf_attr (die, DW_AT_stmt_list);
+  if (!attr)
+    {
+      error (
+        "Dwarf Error: No line number information for compilation unit: %s.",
+        name);
+    }
+  line_offset = DW_UNSND (attr);
+  dwarf_decode_lines (line_offset, abfd);
+
+  /* Process all dies in compilation unit.  */
+  if (die->has_children)
+    {
+      child_die = die->next;
+      while (child_die && child_die->tag)
+       {
+         process_die (child_die, objfile);
+         child_die = sibling_die (child_die);
+       }
+    }
+}
+
+static void
+read_func_scope (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  register struct context_stack *new;
+  CORE_ADDR lowpc  = 0;
+  CORE_ADDR highpc = 0;
+  struct die_info *child_die;
+  struct attribute *attr;
+  struct minimal_symbol *min_sym;
+  char *name = NULL;
+
+  attr = dwarf_attr (die, DW_AT_name);
+  if (attr)
+    {
+      name = DW_STRING (attr);
+    }
+
+  attr = dwarf_attr (die, DW_AT_low_pc);
+  if (attr)
+    {
+      lowpc = DW_ADDR (attr);
+    }
+
+  attr = dwarf_attr (die, DW_AT_high_pc);
+  if (attr)
+    {
+      highpc = DW_ADDR (attr);
+    }
+
+  if (objfile->ei.entry_point >= lowpc &&
+      objfile->ei.entry_point < highpc)
+    {
+      objfile->ei.entry_func_lowpc = lowpc;
+      objfile->ei.entry_func_highpc = highpc;
+    }
+
+  if (STREQ (name, "main"))    /* FIXME: hardwired name */
+    {
+      objfile->ei.main_func_lowpc = lowpc;
+      objfile->ei.main_func_highpc = highpc;
+    }
+  new = push_context (0, lowpc);
+  new->name = new_symbol (die, objfile);
+  list_in_scope = &local_symbols;
+
+  if (die->has_children)
+    {
+      child_die = die->next;
+      while (child_die && child_die->tag)
+       {
+         process_die (child_die, objfile);
+         child_die = sibling_die (child_die);
+       }
+    }
+
+  new = pop_context ();
+  /* Make a block for the local symbols within.  */
+  finish_block (new->name, &local_symbols, new->old_blocks,
+               lowpc, highpc, objfile);
+  list_in_scope = &file_symbols;
+}
+
+/* Process all the DIES contained within a lexical block scope.  Start
+   a new scope, process the dies, and then close the scope.  */
+
+static void
+read_lexical_block_scope (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  register struct context_stack *new;
+  CORE_ADDR lowpc = 0, highpc = 0;
+  struct attribute *attr;
+  struct die_info *child_die;
+
+  attr = dwarf_attr (die, DW_AT_low_pc);
+  if (attr)
+    {
+      lowpc = DW_ADDR (attr);
+    }
+  attr = dwarf_attr (die, DW_AT_high_pc);
+  if (attr)
+    {
+      highpc = DW_ADDR (attr);
+    }
+
+  push_context (0, lowpc);
+  if (die->has_children)
+    {
+      child_die = die->next;
+      while (child_die && child_die->tag)
+       {
+         process_die (child_die, objfile);
+         child_die = sibling_die (child_die);
+       }
+    }
+  new = pop_context ();
+
+  if (local_symbols != NULL)
+    {
+      finish_block (0, &local_symbols, new->old_blocks, new->start_addr,
+                   highpc, objfile);
+    }
+  local_symbols = new->locals;
+}
+
+/* Called when we find the DIE that starts a structure or union scope
+   (definition) to process all dies that define the members of the
+   structure or union.
+
+   NOTE: we need to call struct_type regardless of whether or not the
+   DIE has an at_name attribute, since it might be an anonymous
+   structure or union.  This gets the type entered into our set of
+   user defined types.
+
+   However, if the structure is incomplete (an opaque struct/union)
+   then suppress creating a symbol table entry for it since gdb only
+   wants to find the one with the complete definition.  Note that if
+   it is complete, we just call new_symbol, which does it's own
+   checking about whether the struct/union is anonymous or not (and
+   suppresses creating a symbol table entry itself).  */
+
+static void
+read_structure_scope (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct type *type, *member_type;
+  struct field *fields;
+  struct die_info *child_die;
+  struct attribute *attr;
+  struct symbol *sym;
+  int num_fields;
+
+  type = dwarf_alloc_type (objfile);
+
+  INIT_CPLUS_SPECIFIC (type);
+  attr = dwarf_attr (die, DW_AT_name);
+
+  if (die->tag == DW_TAG_structure_type)
+    {
+      TYPE_CODE (type) = TYPE_CODE_STRUCT;
+      if (attr)
+       {
+         TYPE_NAME (type) = obconcat (&objfile->type_obstack,
+                                    "struct", " ", DW_STRING (attr));
+       }
+    }
+  else
+    {
+      /* die->tag == DW_TAG_union_type */
+      TYPE_CODE (type) = TYPE_CODE_UNION;
+      if (attr)
+       {
+         TYPE_NAME (type) = obconcat (&objfile->type_obstack,
+                                      "union", " ", DW_STRING (attr));
+       }
+    }
+
+  attr = dwarf_attr (die, DW_AT_byte_size);
+  if (attr)
+    {
+      TYPE_LENGTH (type) = DW_UNSND (attr);
+    }
+  else
+    {
+      TYPE_LENGTH (type) = 0;
+    }
+
+  /* We need to add the type field to the die immediately so we don't
+     infinitely recurse when dealing with pointers to the structure
+     type within the structure itself. */
+  die->type = type;
+
+  num_fields = 0;
+  fields = NULL;
+  if (die->has_children)
+    {
+      child_die = die->next;
+      while (child_die && child_die->tag)
+       {
+         if (child_die->tag != DW_TAG_member)
+           {
+             process_die (child_die, objfile);
+           }
+         else
+           {
+             if ((num_fields % DW_FIELD_ALLOC_CHUNK) == 0)
+               {
+                 fields = (struct field *)
+                   xrealloc (fields,
+                             (num_fields + DW_FIELD_ALLOC_CHUNK)
+                              * sizeof (struct field));
+               }
+
+             /* Get bit offset of field */
+             attr = dwarf_attr (child_die, DW_AT_bit_offset);
+             if (attr)
+               {
+                 fields[num_fields].bitpos = DW_UNSND (attr);
+               }
+             else
+               {
+                 fields[num_fields].bitpos = 0;
+               }
+             attr = dwarf_attr (child_die, DW_AT_data_member_location);
+             if (attr)
+               {
+                 fields[num_fields].bitpos +=
+                   decode_locdesc (DW_BLOCK (attr), objfile) * bits_per_byte;
+               }
+
+             /* Get bit size of field (zero if none). */
+             attr = dwarf_attr (child_die, DW_AT_bit_size);
+             if (attr)
+               {
+                 fields[num_fields].bitsize = DW_UNSND (attr);
+               }
+             else
+               {
+                 fields[num_fields].bitsize = 0;
+               }
+
+             /* Get type of member. */
+             member_type = die_type (child_die, objfile);
+             fields[num_fields].type = member_type;
+
+             /* Get name of member. */
+             attr = dwarf_attr (child_die, DW_AT_name);
+             if (attr)
+               {
+                 fields[num_fields].name = obsavestring (DW_STRING (attr),
+                                           strlen (DW_STRING (attr)),
+                                             &objfile->type_obstack);
+#if 0
+                 fields[num_fields].name = strdup (DW_STRING (attr));
+#endif
+               }
+             num_fields++;
+           }
+         child_die = sibling_die (child_die);
+       }
+      type->nfields = num_fields;
+      type->fields = fields;
+    }
+  else
+    {
+      /* No children, must be stub. */
+      TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+    }
+
+  die->type = type;
+  sym = new_symbol (die, objfile);
+  if (sym != NULL)
+    {
+      SYMBOL_TYPE (sym) = type;
+    }
+}
+
+/* Given a pointer to a die which begins an enumeration, process all
+   the dies that define the members of the enumeration.
+
+   This will be much nicer in draft 6 of the DWARF spec when our
+   members will be dies instead squished into the DW_AT_element_list
+   attribute.
+
+   NOTE: We reverse the order of the element list.  */
+
+static void
+read_enumeration (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct die_info *child_die;
+  struct type *type;
+  struct field *fields;
+  struct attribute *attr;
+  struct symbol *sym;
+  struct dwarf_block *blk;
+  int num_fields;
+  unsigned int size, bytes_read, i;
+
+  type = dwarf_alloc_type (objfile);
+
+  TYPE_CODE (type) = TYPE_CODE_ENUM;
+  attr = dwarf_attr (die, DW_AT_name);
+  if (attr)
+    {
+      TYPE_NAME (type) = obconcat (&objfile->type_obstack,
+                                  "enum ", " ", DW_STRING (attr));
+    }
+
+  attr = dwarf_attr (die, DW_AT_byte_size);
+  if (attr)
+    {
+      TYPE_LENGTH (type) = DW_UNSND (attr);
+    }
+  else
+    {
+      TYPE_LENGTH (type) = 0;
+    }
+
+  num_fields = 0;
+  fields = NULL;
+  if (die->has_children)
+    {
+      child_die = die->next;
+      while (child_die && child_die->tag)
+       {
+         if (child_die->tag != DW_TAG_enumerator)
+           {
+             process_die (child_die, objfile);
+           }
+         else
+           {
+             if ((num_fields % DW_FIELD_ALLOC_CHUNK) == 0)
+               {
+                 fields = (struct field *)
+                   xrealloc (fields,
+                     (num_fields + DW_FIELD_ALLOC_CHUNK)
+                       * sizeof (struct field));
+               }
+
+             /* Handcraft a new symbol for this enum member. */
+             sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
+                                             sizeof (struct symbol));
+             memset (sym, 0, sizeof (struct symbol));
+
+             fields[num_fields].type = NULL;
+             fields[num_fields].bitsize = 0;
+             attr = dwarf_attr (child_die, DW_AT_name);
+             if (attr)
+               {
+                 fields[num_fields].name = strdup (DW_STRING (attr));
+                 SYMBOL_NAME (sym) = strdup (fields[num_fields].name);
+               }
+             attr = dwarf_attr (child_die, DW_AT_const_value);
+             if (attr)
+               {
+                 fields[num_fields].bitpos = DW_UNSND (attr);
+                 SYMBOL_VALUE (sym) = DW_UNSND (attr);
+               }
+
+#if 0
+             SYMBOL_NAME (sym) = create_name (elist->str,
+                                           &objfile->symbol_obstack);
+#endif
+             SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+             SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+             SYMBOL_CLASS (sym) = LOC_CONST;
+             SYMBOL_TYPE (sym) = type;
+             add_symbol_to_list (sym, list_in_scope);
+
+             num_fields++;
+           }
+
+         child_die = sibling_die (child_die);
+       }
+      type->fields = fields;
+      type->nfields = num_fields;
+    }
+  die->type = type;
+  sym = new_symbol (die, objfile);
+  if (sym != NULL)
+    {
+      SYMBOL_TYPE (sym) = type;
+    }
+}
+
+/* Extract all information from a DW_TAG_array_type DIE and put it in
+   the DIE's type field.  For now, this only handles one dimensional
+   arrays.  */
+
+static void
+dwarf_read_array_type (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct die_info *child_die;
+  struct type *type, *element_type, *range_type, *index_type;
+  struct attribute *attr;
+  struct dwarf_block *blk;
+  unsigned int size, i, type_form, bytes_read;
+  unsigned int index_spec, lo_spec, hi_spec, type_ref;
+  unsigned int low, high;
+
+  /* Return if we've already decoded this type. */
+  if (die->type)
+    {
+      return;
+    }
+
+  element_type = die_type (die, objfile);
+
+  low = 0;
+  high = 1;
+  if (cu_language == DW_LANG_Fortran77 || cu_language == DW_LANG_Fortran90)
+    {
+      /* FORTRAN implies a lower bound of 1, if not given.  */
+      low = 1;
+    }
+
+  child_die = die->next;
+  while (child_die && child_die->tag)
+    {
+      if (child_die->tag == DW_TAG_subrange_type)
+       {
+         index_type = die_type (child_die, objfile);
+         attr = dwarf_attr (child_die, DW_AT_lower_bound);
+         if (attr)
+           {
+             if (attr->form == DW_FORM_sdata)
+               {
+                 low = DW_SND (attr);
+               }
+             else if (attr->form == DW_FORM_udata
+                      || attr->form == DW_FORM_data1
+                      || attr->form == DW_FORM_data2
+                      || attr->form == DW_FORM_data4)
+               {
+                 low = DW_UNSND (attr);
+               }
+             else
+               {
+                 if (!array_bound_warning_given)
+                   {
+                     warning ("Non-constant array bounds ignored.");
+                     array_bound_warning_given = 1;
+                   }
+#ifdef FORTRAN_HACK
+                 type = dwarf_alloc_type (objfile);
+                 TYPE_TARGET_TYPE (type) = element_type;
+                 TYPE_OBJFILE (type) = objfile;
+                 TYPE_LENGTH (type) = 4;
+                 TYPE_CODE (type) = TYPE_CODE_PTR;
+                 TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
+                 TYPE_POINTER_TYPE (element_type) = type;
+                 goto done;
+#else
+                 low = 0;
+#endif
+               }
+           }
+         attr = dwarf_attr (child_die, DW_AT_upper_bound);
+         if (attr)
+           {
+             if (attr->form == DW_FORM_sdata)
+               {
+                 high = DW_SND (attr);
+               }
+             else if (attr->form == DW_FORM_udata
+                      || attr->form == DW_FORM_data1
+                      || attr->form == DW_FORM_data2
+                      || attr->form == DW_FORM_data4)
+               {
+                 high = DW_UNSND (attr);
+               }
+             else
+               {
+                 if (!array_bound_warning_given)
+                   {
+                     warning ("Non-constant array bounds ignored.");
+                     array_bound_warning_given = 1;
+                   }
+#ifdef FORTRAN_HACK
+                 type = dwarf_alloc_type (objfile);
+                 TYPE_TARGET_TYPE (type) = element_type;
+                 TYPE_OBJFILE (type) = objfile;
+                 TYPE_LENGTH (type) = 4;
+                 TYPE_CODE (type) = TYPE_CODE_PTR;
+                 TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
+                 TYPE_POINTER_TYPE (element_type) = type;
+                 goto done;
+#else
+                 high = 1;
+#endif
+               }
+           }
+       }
+      range_type = create_range_type (NULL, index_type, low, high);
+      type = create_array_type (NULL, element_type, range_type);
+      element_type = type;
+      child_die = sibling_die (child_die);
+    }
+done:
+  /* Install the type in the die. */
+  die->type = type;
+}
+
+/* First cut: install each common block member as a global variable.  */
+
+static void
+read_common_block (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct die_info *child_die;
+  struct attribute *attr;
+  struct symbol *sym;
+  CORE_ADDR base;
+
+  attr = dwarf_attr (die, DW_AT_location);
+  if (attr)
+    {
+      base = decode_locdesc (DW_BLOCK (attr), objfile);
+    }
+  if (die->has_children)
+    {
+      child_die = die->next;
+      while (child_die && child_die->tag)
+       {
+         sym = new_symbol (child_die, objfile);
+         attr = dwarf_attr (child_die, DW_AT_data_member_location);
+         if (attr)
+           {
+             SYMBOL_VALUE_ADDRESS (sym) =
+               base + decode_locdesc (DW_BLOCK (attr), objfile);
+             add_symbol_to_list (sym, &global_symbols);
+           }
+         child_die = sibling_die (child_die);
+       }
+    }
+}
+
+/* Extract all information from a DW_TAG_pointer_type DIE and add to
+   the user defined type vector.  */
+
+static void
+read_tag_pointer_type (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct type *type, *pointed_to_type;
+  struct attribute *attr;
+
+  if (die->type)
+    {
+      return;
+    }
+
+  pointed_to_type = die_type (die, objfile);
+
+  type = dwarf_alloc_type (objfile);
+  TYPE_TARGET_TYPE (type) = pointed_to_type;
+  TYPE_OBJFILE (type) = objfile;
+  attr = dwarf_attr (die, DW_AT_byte_size);
+  if (attr)
+    {
+      TYPE_LENGTH (type) = DW_UNSND (attr);
+    }
+  else
+    {
+      TYPE_LENGTH (type) = address_size;
+    }
+  TYPE_CODE (type) = TYPE_CODE_PTR;
+  TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
+
+  TYPE_POINTER_TYPE (pointed_to_type) = type;
+  die->type = type;
+}
+
+static void
+read_tag_const_type (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  if (die->type)
+    {
+      return;
+    }
+
+  if (!tag_const_warning_given)
+    {
+      warning ("gdb ignores `const' qualifiers.");
+      tag_const_warning_given = 1;
+    }
+
+  die->type = die_type (die, objfile);
+}
+
+static void
+read_tag_volatile_type (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  if (die->type)
+    {
+      return;
+    }
+
+  if (!tag_volatile_warning_given)
+    {
+      warning ("gdb ignores `volatile' qualifiers.");
+      tag_volatile_warning_given = 1;
+    }
+
+  die->type = die_type (die, objfile);
+}
+
+/* Extract all information from a DW_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 (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct type *type, *range_type, *index_type, *char_type;
+  struct attribute *attr;
+  unsigned int length;
+
+  if (die->type)
+    {
+      return;
+    }
+
+  attr = dwarf_attr (die, DW_AT_string_length);
+  if (attr)
+    {
+      length = DW_UNSND (attr);
+    }
+  else
+    {
+      length = 1;
+    }
+  index_type = dwarf2_fundamental_type (objfile, FT_INTEGER);
+  range_type = create_range_type (NULL, index_type, 1, length);
+  char_type = dwarf2_fundamental_type (objfile, FT_CHAR);
+  type = create_string_type (char_type, range_type);
+  die->type = type;
+}
+
+/* Handle DIES due to C code like:
+
+   struct foo
+     {
+       int (*funcp)(int a, long l);
+       int b;
+     };
+
+   ('funcp' generates a DW_TAG_subroutine_type DIE)
+
+   NOTE: parameter DIES are currently ignored.  See if gdb has a way to
+   include this info in it's type system, and decode them if so.  Is
+   this what the type structure's "arg_types" field is for?  (FIXME) */
+
+static void
+read_subroutine_type (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct type *type;           /* Type that this function returns */
+  struct type *ftype;          /* Function that returns above type */
+
+  /* Decode the type that this subroutine returns */
+  if (die->type)
+    {
+      return;
+    }
+  type = die_type (die, objfile);
+  ftype = lookup_function_type (type);
+
+  TYPE_TARGET_TYPE (ftype) = type;
+  TYPE_LENGTH (ftype) = 1;
+  TYPE_CODE (ftype) = TYPE_CODE_FUNC;
+  TYPE_OBJFILE (ftype) = objfile;
+
+  die->type = type;
+}
+
+static void
+read_typedef (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct type *type;
+
+  if (!die->type)
+    {
+      type = die_type (die, objfile);
+      die->type = type;
+    }
+}
+
+/* Find a representation of a given base type and install
+   it in the TYPE field of the die.  */
+
+static void
+read_base_type (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct type *type;
+  struct attribute *attr;
+  int encoding = 0, size = 0;
+
+  /* If we've already decoded this die, this is a no-op. */
+  if (die->type)
+    {
+      return;
+    }
+
+  attr = dwarf_attr (die, DW_AT_encoding);
+  if (attr)
+    {
+      encoding = DW_UNSND (attr);
+    }
+  attr = dwarf_attr (die, DW_AT_byte_size);
+  if (attr)
+    {
+      size = DW_UNSND (attr);
+    }
+  type = dwarf_base_type (encoding, size);
+  die->type = type;
+}
+
+/* Read a whole compilation unit into a linked list of dies.  */
+
+struct die_info *
+read_comp_unit (info_ptr, abfd)
+    char *info_ptr;
+    bfd *abfd;
+{
+  struct die_info *first_die, *last_die, *die;
+  char *cur_ptr;
+  int nesting_level;
+
+  cur_ptr = info_ptr;
+  nesting_level = 0;
+  first_die = last_die = NULL;
+  do
+    {
+      cur_ptr = read_full_die (&die, abfd, cur_ptr);
+      if (die->has_children)
+       {
+         nesting_level++;
+       }
+      if (die->tag == 0)
+       {
+         nesting_level--;
+       }
+
+      die->next = NULL;
+
+      /* Enter die in reference hash table */
+      store_in_ref_table (die->offset, die);
+
+      if (!first_die)
+       {
+         first_die = last_die = die;
+       }
+      else
+       {
+         last_die->next = die;
+         last_die = die;
+       }
+    }
+  while (nesting_level > 0);
+  return first_die;
+}
+
+/* Free a linked list of dies.  */
+
+static void
+free_die_list (dies)
+     struct die_info *dies;
+{
+  struct die_info *die, *next;
+
+  die = dies;
+  while (die)
+    {
+      next = die->next;
+      free (die->attrs);
+      free (die);
+      die = next;
+    }
+}
+
+/* Read the contents of the section at OFFSET and of size SIZE in the
+   object file specified by ABFD into a buffer of bytes and return it.  */
+
+static char *
+dwarf2_read_section (abfd, offset, size)
+     bfd * abfd;
+     file_ptr offset;
+     unsigned int size;
+{
+  char *buf;
+
+  buf = xmalloc (size);
+  if ((bfd_seek (abfd, offset, SEEK_SET) != 0) ||
+      (bfd_read (buf, size, 1, abfd) != size))
+    {
+      free (buf);
+      buf = NULL;
+      error ("Dwarf Error: Can't read DWARF data from '%s'",
+        bfd_get_filename (abfd));
+    }
+  return buf;
+}
+
+/* In DWARF version 2, the description of the debugging information is
+   stored in a separate .debug_abbrev section.  Before we read any
+   dies from a section we read in all abbreviations and install them
+   in a hash table.  */
+
+static void
+dwarf2_read_abbrevs (abfd, offset)
+     bfd * abfd;
+     unsigned int offset;
+{
+  char *abbrev_ptr;
+  struct abbrev_info *cur_abbrev;
+  unsigned int abbrev_number, bytes_read, abbrev_name;
+  unsigned int abbrev_form, hash_number;
+
+  /* empty the table */
+  dwarf2_empty_abbrev_table ();
+
+  abbrev_ptr = dwarf_abbrev_buffer + offset;
+  abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+  abbrev_ptr += bytes_read;
+
+  /* loop until we reach an abbrev number of 0 */
+  while (abbrev_number)
+    {
+      cur_abbrev = dwarf_alloc_abbrev ();
+
+      /* read in abbrev header */
+      cur_abbrev->number = abbrev_number;
+      cur_abbrev->tag = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+      abbrev_ptr += bytes_read;
+      cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr);
+      abbrev_ptr += 1;
+
+      /* now read in declarations */
+      abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+      abbrev_ptr += bytes_read;
+      abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+      abbrev_ptr += bytes_read;
+      while (abbrev_name)
+       {
+         if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0)
+           {
+             cur_abbrev->attrs = xrealloc (cur_abbrev->attrs,
+                           (cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK)
+                                      * sizeof (struct attr_abbrev));
+           }
+         cur_abbrev->attrs[cur_abbrev->num_attrs].name = abbrev_name;
+         cur_abbrev->attrs[cur_abbrev->num_attrs++].form = abbrev_form;
+         abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+         abbrev_ptr += bytes_read;
+         abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+         abbrev_ptr += bytes_read;
+       }
+
+      hash_number = abbrev_number % ABBREV_HASH_SIZE;
+      cur_abbrev->next = dwarf2_abbrevs[hash_number];
+      dwarf2_abbrevs[hash_number] = cur_abbrev;
+
+      /* get next abbrev */
+      abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+      abbrev_ptr += bytes_read;
+    }
+}
+
+/* Empty the abbrev table for a new compilation unit.  */
+
+static void
+dwarf2_empty_abbrev_table ()
+{
+  int i;
+  struct abbrev_info *abbrev, *next;
+
+  for (i = 0; i < ABBREV_HASH_SIZE; ++i)
+    {
+      next = NULL;
+      abbrev = dwarf2_abbrevs[i];
+      while (abbrev)
+       {
+         next = abbrev->next;
+         free (abbrev->attrs);
+         free (abbrev);
+         abbrev = next;
+       }
+      dwarf2_abbrevs[i] = NULL;
+    }
+}
+
+/* Lookup an abbrev_info structure in the abbrev hash table.  */
+
+static struct abbrev_info *
+dwarf2_lookup_abbrev (number)
+     unsigned int number;
+{
+  unsigned int hash_number;
+  struct abbrev_info *abbrev;
+
+  hash_number = number % ABBREV_HASH_SIZE;
+  abbrev = dwarf2_abbrevs[hash_number];
+
+  while (abbrev)
+    {
+      if (abbrev->number == number)
+       return abbrev;
+      else
+       abbrev = abbrev->next;
+    }
+  return NULL;
+}
+
+/* Read a minimal amount of information into the minimal die structure.  */
+
+static char *
+read_partial_die (part_die, abfd, info_ptr, has_pc_info)
+     struct partial_die_info *part_die;
+     bfd * abfd;
+     char *info_ptr;
+     int *has_pc_info;
+{
+  unsigned int abbrev_number, bytes_read, i;
+  struct abbrev_info *abbrev;
+  char ebuf[256];
+  int has_low_pc_attr  = 0;
+  int has_high_pc_attr = 0;
+
+  *has_pc_info = 0;
+  abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+  info_ptr += bytes_read;
+  if (!abbrev_number)
+    {
+      part_die->tag = 0;
+      part_die->has_children = 0;
+      part_die->abbrev = abbrev_number;
+      return info_ptr;
+    }
+
+  abbrev = dwarf2_lookup_abbrev (abbrev_number);
+  if (!abbrev)
+    {
+      error ("Dwarf Error: Could not find abbrev number %d.", abbrev_number);
+    }
+  part_die->offset = info_ptr - dwarf_info_buffer;
+  part_die->tag = abbrev->tag;
+  part_die->has_children = abbrev->has_children;
+  part_die->is_external = 0;
+  part_die->abbrev = abbrev_number;
+
+  {
+    char *str = "";
+    struct dwarf_block *blk = 0;
+    CORE_ADDR addr = ((CORE_ADDR) -1);
+    unsigned int unsnd = ((unsigned int) -1);
+    int snd = -1;
+
+    for (i = 0; i < abbrev->num_attrs; ++i)
+      {
+       /* read the correct type of data */
+       switch (abbrev->attrs[i].form)
+         {
+         case DW_FORM_addr:
+           addr = read_address (abfd, info_ptr);
+           info_ptr += address_size;
+           break;
+         case DW_FORM_ref_addr:
+           addr = read_address (abfd, info_ptr);
+           info_ptr += address_size;
+           break;
+         case DW_FORM_block2:
+           blk = dwarf_alloc_block ();
+           blk->size = read_2_bytes (abfd, info_ptr);
+           info_ptr += 2;
+           blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+           info_ptr += blk->size;
+           break;
+         case DW_FORM_block4:
+           blk = dwarf_alloc_block ();
+           blk->size = read_4_bytes (abfd, info_ptr);
+           info_ptr += 2;
+           blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+           info_ptr += blk->size;
+           break;
+         case DW_FORM_data2:
+           unsnd = read_2_bytes (abfd, info_ptr);
+           info_ptr += 2;
+           break;
+         case DW_FORM_data4:
+           unsnd = read_4_bytes (abfd, info_ptr);
+           info_ptr += 4;
+           break;
+         case DW_FORM_data8:
+           unsnd = read_8_bytes (abfd, info_ptr);
+           info_ptr += 8;
+           break;
+         case DW_FORM_string:
+           str = read_string (abfd, info_ptr, &bytes_read);
+           info_ptr += bytes_read;
+           break;
+         case DW_FORM_block:
+           blk = dwarf_alloc_block ();
+           blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+           info_ptr += bytes_read;
+           blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+           info_ptr += blk->size;
+           break;
+         case DW_FORM_block1:
+           blk = dwarf_alloc_block ();
+           blk->size = read_1_byte (abfd, info_ptr);
+           info_ptr += 1;
+           blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+           info_ptr += blk->size;
+           break;
+         case DW_FORM_data1:
+           unsnd = read_1_byte (abfd, info_ptr);
+           info_ptr += 1;
+           break;
+         case DW_FORM_ref1:
+           unsnd = read_1_byte (abfd, info_ptr);
+           info_ptr += 1;
+           break;
+         case DW_FORM_ref2:
+           unsnd = read_2_bytes (abfd, info_ptr);
+           info_ptr += 2;
+           break;
+         case DW_FORM_ref4:
+           unsnd = read_4_bytes (abfd, info_ptr);
+           info_ptr += 4;
+           break;
+         case DW_FORM_ref_udata:
+           unsnd = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+           info_ptr += bytes_read;
+           break;
+         case DW_FORM_flag:
+           unsnd = read_1_byte (abfd, info_ptr);
+           info_ptr += 1;
+           break;
+         case DW_FORM_sdata:
+           snd = read_signed_leb128 (abfd, info_ptr, &bytes_read);
+           info_ptr += bytes_read;
+           break;
+         case DW_FORM_udata:
+           unsnd = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+           info_ptr += bytes_read;
+           break;
+         case DW_FORM_indirect:
+         default:
+           sprintf (ebuf,
+                    "Dwarf Error: Cannot handle %s in DWARF reader.",
+                    dwarf_form_name (abbrev->attrs[i].form));
+           error (ebuf);
+         }
+
+       /* store the data if it is of an attribute we want to keep in a
+          partial symbol table */
+       switch (abbrev->attrs[i].name)
+         {
+         case DW_AT_name:
+           part_die->name = str;
+           break;
+         case DW_AT_low_pc:
+           has_low_pc_attr = 1;
+           part_die->lowpc = addr;
+           break;
+         case DW_AT_high_pc:
+           has_high_pc_attr = 1;
+           part_die->highpc = addr;
+           break;
+         case DW_AT_location:
+           part_die->locdesc = blk;
+           break;
+         case DW_AT_language:
+           part_die->language = unsnd;
+           break;
+         case DW_AT_external:
+           part_die->is_external = unsnd;
+         }
+      }
+  }
+  *has_pc_info = has_low_pc_attr && has_high_pc_attr;
+  return info_ptr;
+}
+
+/* Read the die from the .debug_info section buffer.  And set diep to
+   point to a newly allocated die with its information.  */
+
+static char *
+read_full_die (diep, abfd, info_ptr)
+     struct die_info **diep;
+     bfd *abfd;
+     char *info_ptr;
+{
+  unsigned int abbrev_number, bytes_read, i, offset;
+  struct abbrev_info *abbrev;
+  struct die_info *die;
+  char ebuf[256];
+
+  offset = info_ptr - dwarf_info_buffer;
+  abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+  info_ptr += bytes_read;
+  if (!abbrev_number)
+    {
+      die = dwarf_alloc_die ();
+      die->tag = 0;
+      die->abbrev = abbrev_number;
+      die->type = NULL;
+      *diep = die;
+      return info_ptr;
+    }
+
+  abbrev = dwarf2_lookup_abbrev (abbrev_number);
+  if (!abbrev)
+    {
+      error ("Dwarf Error: could not find abbrev number %d.", abbrev_number);
+    }
+  die = dwarf_alloc_die ();
+  die->offset = offset;
+  die->tag = abbrev->tag;
+  die->has_children = abbrev->has_children;
+  die->abbrev = abbrev_number;
+  die->type = NULL;
+
+  die->num_attrs = abbrev->num_attrs;
+  die->attrs = xmalloc (die->num_attrs * sizeof (struct attribute));
+
+  {
+    char *str;
+    struct dwarf_block *blk;
+    unsigned long addr;
+    unsigned int unsnd;
+    int snd;
+
+    for (i = 0; i < abbrev->num_attrs; ++i)
+      {
+       /* read the correct type of data */
+
+       die->attrs[i].name = abbrev->attrs[i].name;
+       die->attrs[i].form = abbrev->attrs[i].form;
+
+       switch (abbrev->attrs[i].form)
+         {
+         case DW_FORM_addr:
+         case DW_FORM_ref_addr:
+           die->attrs[i].u.addr = read_address (abfd, info_ptr);
+           info_ptr += address_size;
+           break;
+         case DW_FORM_block2:
+           blk = dwarf_alloc_block ();
+           blk->size = read_2_bytes (abfd, info_ptr);
+           info_ptr += 2;
+           blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+           info_ptr += blk->size;
+           die->attrs[i].u.blk = blk;
+           break;
+         case DW_FORM_block4:
+           blk = dwarf_alloc_block ();
+           blk->size = read_4_bytes (abfd, info_ptr);
+           info_ptr += 2;
+           blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+           info_ptr += blk->size;
+           die->attrs[i].u.blk = blk;
+           break;
+         case DW_FORM_data2:
+           die->attrs[i].u.unsnd = read_2_bytes (abfd, info_ptr);
+           info_ptr += 2;
+           break;
+         case DW_FORM_data4:
+           die->attrs[i].u.unsnd = read_4_bytes (abfd, info_ptr);
+           info_ptr += 4;
+           break;
+         case DW_FORM_data8:
+           die->attrs[i].u.unsnd = read_8_bytes (abfd, info_ptr);
+           info_ptr += 8;
+           break;
+         case DW_FORM_string:
+           die->attrs[i].u.str = read_string (abfd, info_ptr, &bytes_read);
+           info_ptr += bytes_read;
+           break;
+         case DW_FORM_block:
+           blk = dwarf_alloc_block ();
+           blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+           info_ptr += bytes_read;
+           blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+           info_ptr += blk->size;
+           die->attrs[i].u.blk = blk;
+           break;
+         case DW_FORM_block1:
+           blk = dwarf_alloc_block ();
+           blk->size = read_1_byte (abfd, info_ptr);
+           info_ptr += 1;
+           blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+           info_ptr += blk->size;
+           die->attrs[i].u.blk = blk;
+           break;
+         case DW_FORM_data1:
+           die->attrs[i].u.unsnd = read_1_byte (abfd, info_ptr);
+           info_ptr += 1;
+           break;
+         case DW_FORM_ref1:
+           die->attrs[i].u.unsnd = read_1_byte (abfd, info_ptr);
+           info_ptr += 1;
+           break;
+         case DW_FORM_ref2:
+           die->attrs[i].u.unsnd = read_2_bytes (abfd, info_ptr);
+           info_ptr += 2;
+           break;
+         case DW_FORM_ref4:
+           die->attrs[i].u.unsnd = read_4_bytes (abfd, info_ptr);
+           info_ptr += 4;
+           break;
+         case DW_FORM_ref_udata:
+           die->attrs[i].u.unsnd = read_unsigned_leb128 (abfd,
+                                                         info_ptr,
+                                                         &bytes_read);
+           info_ptr += bytes_read;
+           break;
+         case DW_FORM_flag:
+           die->attrs[i].u.unsnd = read_1_byte (abfd, info_ptr);
+           info_ptr += 1;
+           break;
+         case DW_FORM_sdata:
+           die->attrs[i].u.snd = read_signed_leb128 (abfd,
+                                                     info_ptr,
+                                                     &bytes_read);
+           info_ptr += bytes_read;
+           break;
+         case DW_FORM_udata:
+           die->attrs[i].u.unsnd = read_unsigned_leb128 (abfd,
+                                                         info_ptr,
+                                                         &bytes_read);
+           info_ptr += bytes_read;
+           break;
+         case DW_FORM_indirect:
+         default:
+           sprintf (ebuf,
+                    "Dwarf Error: Cannot handle %s in DWARF reader.",
+                    dwarf_form_name (abbrev->attrs[i].form));
+           error (ebuf);
+         }
+
+      }
+  }
+  *diep = die;
+  return info_ptr;
+}
+
+/* read dwarf information from a buffer */
+
+static unsigned int
+read_1_byte (abfd, buf)
+     bfd *abfd;
+     char *buf;
+{
+  return bfd_get_8 (abfd, (bfd_byte *) buf);
+}
+
+static unsigned int
+read_2_bytes (abfd, buf)
+     bfd *abfd;
+     char *buf;
+{
+  return bfd_get_16 (abfd, (bfd_byte *) buf);
+}
+
+static unsigned int
+read_4_bytes (abfd, buf)
+     bfd *abfd;
+     char *buf;
+{
+  return bfd_get_32 (abfd, (bfd_byte *) buf);
+}
+
+static unsigned int
+read_8_bytes (abfd, buf)
+     bfd *abfd;
+     char *buf;
+{
+  return bfd_get_64 (abfd, (bfd_byte *) buf);
+}
+
+static CORE_ADDR
+read_address (abfd, buf)
+     bfd *abfd;
+     char *buf;
+{
+  CORE_ADDR retval = 0;
+
+  if (address_size == 4)
+    {
+      retval = bfd_get_32 (abfd, (bfd_byte *) buf);
+    } else {                   /* *THE* alternative is 8, right? */
+      retval = bfd_get_64 (abfd, (bfd_byte *) buf);
+    }
+  return retval;
+}
+
+static char *
+read_n_bytes (abfd, buf, size)
+     bfd * abfd;
+     char *buf;
+     unsigned int size;
+{
+  char *ret;
+  unsigned int i;
+
+  ret = xmalloc (size);
+  for (i = 0; i < size; ++i)
+    {
+      ret[i] = bfd_get_8 (abfd, (bfd_byte *) buf);
+      buf++;
+    }
+  return ret;
+}
+
+/* FIXME : hardwired string size limit */
+
+static char *
+read_string (abfd, buf, bytes_read_ptr)
+     bfd *abfd;
+     char *buf;
+     unsigned int *bytes_read_ptr;
+{
+  char ret_buf[DWARF2_MAX_STRING_SIZE], *ret, byte;
+  unsigned int i;
+
+  i = 0;
+  do
+    {
+      byte = bfd_get_8 (abfd, (bfd_byte *) buf);
+      buf++;
+      ret_buf[i++] = byte;
+    }
+  while (byte);
+  if (i == 1)
+    {
+      *bytes_read_ptr = 1;
+      return NULL;
+    }
+  ret = xmalloc (i);
+  strncpy (ret, ret_buf, i);
+  *bytes_read_ptr = i;
+  return ret;
+}
+
+static unsigned int
+read_unsigned_leb128 (abfd, buf, bytes_read_ptr)
+     bfd *abfd;
+     char *buf;
+     unsigned int *bytes_read_ptr;
+{
+  unsigned int result, num_read;
+  int i, shift;
+  unsigned char byte;
+
+  result = 0;
+  shift = 0;
+  num_read = 0;
+  i = 0;
+  while (1)
+    {
+      byte = bfd_get_8 (abfd, (bfd_byte *) buf);
+      buf++;
+      num_read++;
+      result |= ((byte & 127) << shift);
+      if ((byte & 128) == 0)
+       {
+         break;
+       }
+      shift += 7;
+    }
+  *bytes_read_ptr = num_read;
+  return result;
+}
+
+static int
+read_signed_leb128 (abfd, buf, bytes_read_ptr)
+     bfd *abfd;
+     char *buf;
+     unsigned int *bytes_read_ptr;
+{
+  int result;
+  int i, shift, size, num_read;
+  unsigned char byte;
+
+  result = 0;
+  shift = 0;
+  size = 32;
+  num_read = 0;
+  i = 0;
+  while (1)
+    {
+      byte = bfd_get_8 (abfd, (bfd_byte *) buf);
+      buf++;
+      num_read++;
+      result |= ((byte & 127) << shift);
+      shift += 7;
+      if ((byte & 128) == 0)
+       {
+         break;
+       }
+    }
+  if ((shift < size) && (byte & 0x40))
+    {
+      result |= -(1 << shift);
+    }
+  *bytes_read_ptr = num_read;
+  return result;
+}
+
+static void
+set_cu_language (lang)
+     unsigned int lang;
+{
+  switch (lang)
+    {
+    case DW_LANG_C89:
+    case DW_LANG_C:
+    case DW_LANG_Fortran77:
+      cu_language = language_c;
+      break;
+    case DW_LANG_C_plus_plus:
+      cu_language = language_cplus;
+      break;
+    case DW_LANG_Ada83:
+    case DW_LANG_Cobol74:
+    case DW_LANG_Cobol85:
+#if 0
+    case DW_LANG_Fortran77:    /* moved up top for now */
+#endif
+    case DW_LANG_Fortran90:
+    case DW_LANG_Pascal83:
+    case DW_LANG_Modula2:
+    default:
+      cu_language = language_unknown;
+      break;
+    }
+  cu_language_defn = language_def (cu_language);
+}
+
+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, objfile);
+}
+
+/* Converts a location description into gdb form.  */
+
+static int
+convert_locdesc (blk)
+     struct dwarf_block *blk;
+{
+  /* FIXME : this is only a stub! */
+  return 0;
+}
+
+/* Return the named attribute or NULL if not there.  */
+
+static struct attribute *
+dwarf_attr (die, name)
+     struct die_info *die;
+     unsigned int name;
+{
+  unsigned int i;
+
+  for (i = 0; i < die->num_attrs; ++i)
+    {
+      if (die->attrs[i].name == name)
+       {
+         return &die->attrs[i];
+       }
+    }
+  return NULL;
+}
+
+/* Decode the line number information for the compilation unit whose
+   line number info is at OFFSET in the .debug_line section.  */
+
+struct filenames
+{
+  int num_files;
+  struct file
+  {
+    char *name;
+    unsigned int dir;
+    unsigned int time;
+    unsigned int size;
+  }
+  *files;
+};
+
+struct directories
+{
+  int num_dirs;
+  char **dirs;
+};
+
+static void
+dwarf_decode_lines (offset, abfd)
+     unsigned int offset;
+     bfd *abfd;
+{
+  char *line_ptr;
+  struct line_head lh;
+  struct cleanup *back_to;
+  unsigned int i, bytes_read;
+  char *cur_file, *cur_dir;
+  unsigned char op_code, extended_op, adj_opcode;
+
+#define FILE_ALLOC_CHUNK 5
+#define DIR_ALLOC_CHUNK 5
+
+  struct filenames files;
+  struct directories dirs;
+
+  /* state machine registers  */
+  unsigned int address = 0;
+  unsigned int file = 1;
+  unsigned int line = 1;
+  unsigned int column = 0;
+  int is_stmt;                 /* initialized below */
+  int basic_block = 0;
+  int beg_of_comp_unit = 0;    /* is this right? */
+  int end_sequence = 0;
+
+  files.num_files = 0;
+  files.files = NULL;
+
+  dirs.num_dirs = 0;
+  dirs.dirs = NULL;
+
+  line_ptr = dwarf_line_buffer + offset;
+
+  /* read in the prologue */
+  lh.total_length = read_4_bytes (abfd, line_ptr);
+  line_ptr += 4;
+  lh.version = read_2_bytes (abfd, line_ptr);
+  line_ptr += 2;
+  lh.prologue_length = read_4_bytes (abfd, line_ptr);
+  line_ptr += 4;
+  lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
+  line_ptr += 1;
+  lh.default_is_stmt = read_1_byte (abfd, line_ptr);
+  is_stmt = lh.default_is_stmt;
+  line_ptr += 1;
+  lh.line_base = read_1_byte (abfd, line_ptr);
+  line_ptr += 1;
+  lh.line_range = read_1_byte (abfd, line_ptr);
+  line_ptr += 1;
+  lh.opcode_base = read_1_byte (abfd, line_ptr);
+  line_ptr += 1;
+  lh.standard_opcode_lengths = (unsigned char *)
+    xmalloc (lh.opcode_base * sizeof (unsigned char));
+  back_to = make_cleanup (free, lh.standard_opcode_lengths);
+
+  lh.standard_opcode_lengths[0] = 1;
+  for (i = 1; i < lh.opcode_base; ++i)
+    {
+      lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
+      line_ptr += 1;
+    }
+
+  /* Read directory table  */
+  while (cur_dir = read_string (abfd, line_ptr, &bytes_read))
+    {
+      line_ptr += bytes_read;
+      if ((dirs.num_dirs % DIR_ALLOC_CHUNK) == 0)
+       {
+         dirs.dirs = xrealloc (dirs.dirs,
+           (dirs.num_dirs + DIR_ALLOC_CHUNK) * sizeof (char *));
+       }
+      dirs.dirs[dirs.num_dirs++] = cur_dir;
+    }
+  line_ptr += bytes_read;
+
+  /* Read file name table */
+  while (cur_file = read_string (abfd, line_ptr, &bytes_read))
+    {
+      line_ptr += bytes_read;
+      if ((files.num_files % FILE_ALLOC_CHUNK) == 0)
+       {
+         files.files = xrealloc (files.files,
+           (files.num_files + FILE_ALLOC_CHUNK) * sizeof (struct file));
+       }
+      files.files[files.num_files].name = cur_file;
+      files.files[files.num_files].dir = read_unsigned_leb128 (abfd,
+                                          line_ptr, &bytes_read);
+      line_ptr += bytes_read;
+      files.files[files.num_files].time = read_unsigned_leb128 (abfd,
+                                          line_ptr, &bytes_read);
+      line_ptr += bytes_read;
+      files.files[files.num_files].size = read_unsigned_leb128 (abfd,
+                                          line_ptr, &bytes_read);
+      line_ptr += bytes_read;
+      files.num_files++;
+    }
+  line_ptr += bytes_read;
+
+  /* Decode the table. */
+  if (lh.total_length - (lh.prologue_length + 4 + 2) >= 4)
+    do
+      {
+       op_code = read_1_byte (abfd, line_ptr);
+       line_ptr += 1;
+       switch (op_code)
+         {
+         case DW_LNS_extended_op:
+           line_ptr += 1;      /* ignore length */
+           extended_op = read_1_byte (abfd, line_ptr);
+           line_ptr += 1;
+           switch (extended_op)
+             {
+             case DW_LNE_end_sequence:
+               end_sequence = 1;
+               record_line (current_subfile, line, address);
+               return;         /* return! */
+               break;
+             case DW_LNE_set_address:
+               address = read_address (abfd, line_ptr);
+               line_ptr += address_size;
+               break;
+             case DW_LNE_define_file:
+               cur_file = read_string (abfd, line_ptr, &bytes_read);
+               line_ptr += bytes_read;
+               if ((files.num_files % FILE_ALLOC_CHUNK) == 0)
+                 {
+                   files.files = xrealloc (files.files,
+                     (files.num_files + FILE_ALLOC_CHUNK)
+                       * sizeof (struct file));
+                 }
+               files.files[files.num_files].name = cur_file;
+               files.files[files.num_files].dir = read_unsigned_leb128 (
+                 abfd, line_ptr, &bytes_read);
+               line_ptr += bytes_read;
+               files.files[files.num_files].time = read_unsigned_leb128 (abfd,
+                 line_ptr, &bytes_read);
+               line_ptr += bytes_read;
+               files.files[files.num_files].size = read_unsigned_leb128 (abfd,
+                 line_ptr, &bytes_read);
+               line_ptr += bytes_read;
+               break;
+             default:
+               error ("Dwarf Error: Mangled .debug_line section.");
+               return;
+             }
+           break;
+         case DW_LNS_copy:
+           record_line (current_subfile, line, address);
+           basic_block = 0;
+           break;
+         case DW_LNS_advance_pc:
+           address += lh.minimum_instruction_length
+             * read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+           line_ptr += bytes_read;
+           break;
+         case DW_LNS_advance_line:
+           line += read_signed_leb128 (abfd, line_ptr, &bytes_read);
+           line_ptr += bytes_read;
+           break;
+         case DW_LNS_set_file:
+           /* The file table is 0 based and the references are 1
+              based, thus  the subtraction of `1' at the end of the
+              next line */
+           file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read) - 1;
+           start_subfile (files.files[file].name,
+                          (files.files[file].dir ?
+                            dirs.dirs[files.files[file].dir] : 0));
+           line_ptr += bytes_read;
+           break;
+         case DW_LNS_set_column:
+           column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+           line_ptr += bytes_read;
+           break;
+         case DW_LNS_negate_stmt:
+           is_stmt = (!is_stmt);
+           break;
+         case DW_LNS_set_basic_block:
+           basic_block = 1;
+           break;
+         case DW_LNS_const_add_pc:
+           address += (255 - lh.opcode_base) / lh.line_range;
+           break;
+         case DW_LNS_fixed_advance_pc:
+           address += read_2_bytes (abfd, line_ptr);
+           line_ptr += 2;
+           break;
+         default:              /* special operand */
+           adj_opcode = op_code - lh.opcode_base;
+           address += (adj_opcode / lh.line_range)
+             * lh.minimum_instruction_length;
+           line += lh.line_base + (adj_opcode % lh.line_range);
+           /* append row to matrix using current values */
+           record_line (current_subfile, line, address);
+           basic_block = 1;
+         }
+      }
+    while (1);
+  do_cleanups (back_to);
+}
+
+/* Given a pointer to a DWARF information entry, figure out if we need
+   to make a symbol table entry for it, and if so, create a new entry
+   and return a pointer to it.  */
+
+static struct symbol *
+new_symbol (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct symbol *sym = NULL;
+  struct attribute *attr = NULL;
+  struct attribute *attr2 = NULL;
+  CORE_ADDR addr;
+
+  attr = dwarf_attr (die, DW_AT_name);
+  if (attr)
+    {
+#if 0
+      sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
+                                            sizeof (struct symbol));
+#endif
+      sym = (struct symbol *) xmalloc (sizeof (struct symbol));
+      memset (sym, 0, sizeof (struct symbol));
+#if 0
+      SYMBOL_NAME (sym) = create_name (DW_STRING (attr),
+                                      &objfile->symbol_obstack);
+#endif
+      SYMBOL_NAME (sym) = strdup (DW_STRING (attr));
+      /* default assumptions */
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      SYMBOL_CLASS (sym) = LOC_STATIC;
+      SYMBOL_TYPE (sym) = die_type (die, objfile);
+
+      /* 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 (die->tag)
+       {
+       case DW_TAG_label:
+         attr = dwarf_attr (die, DW_AT_low_pc);
+         if (attr)
+           {
+             SYMBOL_VALUE_ADDRESS (sym) = DW_ADDR (attr);
+           }
+         SYMBOL_CLASS (sym) = LOC_LABEL;
+         break;
+       case DW_TAG_subprogram:
+         attr = dwarf_attr (die, DW_AT_low_pc);
+         if (attr)
+           {
+             SYMBOL_VALUE_ADDRESS (sym) = DW_ADDR (attr);
+           }
+         SYMBOL_TYPE (sym) = make_function_type (die_type (die, objfile),
+                                                 NULL);
+         SYMBOL_CLASS (sym) = LOC_BLOCK;
+         attr2 = dwarf_attr (die, DW_AT_external);
+         if (attr2 && (DW_UNSND (attr2) != 0))
+           {
+             add_symbol_to_list (sym, &global_symbols);
+           }
+         else
+           {
+             add_symbol_to_list (sym, list_in_scope);
+           }
+         break;
+       case DW_TAG_variable:
+         attr = dwarf_attr (die, DW_AT_location);
+         if (attr)
+           {
+             attr2 = dwarf_attr (die, DW_AT_external);
+             if (attr2 && (DW_UNSND (attr2) != 0))
+               {
+                 SYMBOL_VALUE_ADDRESS (sym) =
+                   decode_locdesc (DW_BLOCK (attr), objfile);
+                 add_symbol_to_list (sym, &global_symbols);
+                 SYMBOL_CLASS (sym) = LOC_STATIC;
+                 SYMBOL_VALUE_ADDRESS (sym) += baseaddr;
+               }
+             else
+               {
+                 SYMBOL_VALUE (sym) = addr =
+                   decode_locdesc (DW_BLOCK (attr), objfile);
+                 add_symbol_to_list (sym, list_in_scope);
+                 if (isreg)
+                   {
+                     SYMBOL_CLASS (sym) = LOC_REGISTER;
+                   }
+                 else if (offreg)
+                   {
+                     SYMBOL_CLASS (sym) = LOC_LOCAL;
+                   }
+                 else
+                   {
+                     SYMBOL_CLASS (sym) = LOC_STATIC;
+                     SYMBOL_VALUE_ADDRESS (sym) = addr + baseaddr;
+                   }
+               }
+           }
+         break;
+       case DW_TAG_formal_parameter:
+         attr = dwarf_attr (die, DW_AT_location);
+         if (attr != NULL)
+           {
+             SYMBOL_VALUE (sym) = decode_locdesc (DW_BLOCK (attr), objfile);
+           }
+         add_symbol_to_list (sym, list_in_scope);
+         if (isreg)
+           {
+             SYMBOL_CLASS (sym) = LOC_REGPARM;
+           }
+         else
+           {
+             SYMBOL_CLASS (sym) = LOC_ARG;
+           }
+         break;
+       case DW_TAG_unspecified_parameters:
+         /* From varargs functions; gdb doesn't seem to have any
+            interest in this information, so just ignore it for now.
+            (FIXME?) */
+         break;
+       case DW_TAG_class_type:
+       case DW_TAG_structure_type:
+       case DW_TAG_union_type:
+       case DW_TAG_enumeration_type:
+         SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+         SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+         add_symbol_to_list (sym, list_in_scope);
+         break;
+       case DW_TAG_typedef:
+         SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+         SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+         add_symbol_to_list (sym, list_in_scope);
+         break;
+       default:
+         /* Not a tag we recognize.  Hopefully we aren't processing
+            trash data, but since we must specifically ignore things
+            we don't recognize, there is nothing else we should do at
+            this point. */
+         break;
+       }
+    }
+  return (sym);
+}
+
+/* Return the type of the die in question using its DW_AT_type attribute.  */
+
+static struct type *
+die_type (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  struct type *type;
+  struct attribute *attr, *type_attr;
+  struct die_info *type_die;
+  unsigned int size = 0, encoding = 0, ref;
+
+  type_attr = dwarf_attr (die, DW_AT_type);
+  if (!type_attr)
+    {
+      type = dwarf_base_type (0, 0);
+      return type;
+    }
+  else
+    {
+      ref = DW_UNSND (type_attr);
+      type_die = follow_die_ref (ref);
+      if (!type_die)
+       {
+         error ("Dwarf Error: Cannot find referent at offset %d.", ref);
+         return NULL;
+       }
+    }
+  type = tag_type_to_type (type_die, objfile);
+  if (!type)
+    {
+      error ("Dwarf Error: Problem turning type die at offset into gdb type:");
+      dump_die (type_die);
+    }
+  return type;
+}
+
+static struct type *
+type_at_offset (offset, objfile)
+     unsigned int offset;
+     struct objfile *objfile;
+{
+  struct die_info *die;
+  struct type *type;
+
+  die = follow_die_ref (offset);
+  if (!die)
+    {
+      error ("Dwarf Error: Cannot find type referent at offset %d.", offset);
+      return NULL;
+    }
+  type = tag_type_to_type (die, objfile);
+  return type;
+}
+
+static struct type *
+tag_type_to_type (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  if (die->type)
+    {
+      return die->type;
+    }
+  else
+    {
+      read_type_die (die, objfile);
+      if (!die->type)
+       {
+         dump_die (die);
+         error ("Dwarf Error: Cannot find type of die:");
+       }
+      return die->type;
+    }
+}
+
+static void
+read_type_die (die, objfile)
+     struct die_info *die;
+     struct objfile *objfile;
+{
+  switch (die->tag)
+    {
+    case DW_TAG_class_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_union_type:
+      read_structure_scope (die, objfile);
+      break;
+    case DW_TAG_enumeration_type:
+      read_enumeration (die, objfile);
+      break;
+    case DW_TAG_subroutine_type:
+      read_subroutine_type (die, objfile);
+      break;
+    case DW_TAG_array_type:
+      dwarf_read_array_type (die, objfile);
+      break;
+    case DW_TAG_pointer_type:
+      read_tag_pointer_type (die, objfile);
+      break;
+    case DW_TAG_const_type:
+      read_tag_const_type (die, objfile);
+      break;
+    case DW_TAG_volatile_type:
+      read_tag_volatile_type (die, objfile);
+      break;
+    case DW_TAG_string_type:
+      read_tag_string_type (die, objfile);
+      break;
+    case DW_TAG_typedef:
+      read_typedef (die, objfile);
+      break;
+    case DW_TAG_base_type:
+      read_base_type (die, objfile);
+      break;
+    case DW_TAG_padding:
+    case DW_TAG_compile_unit:
+    case DW_TAG_subprogram:
+    case DW_TAG_lexical_block:
+    default:
+      break;
+    }
+}
+
+static struct type *
+dwarf_base_type (encoding, size)
+     int encoding;
+     int size;
+{
+  /* FIXME - this should not produce a new (struct type *)
+     every time.  It should cache base types.  */
+  struct type *type;
+  switch (encoding)
+    {
+    case DW_ATE_address:
+      type = dwarf2_fundamental_type (current_objfile, FT_VOID);
+      return type;
+    case DW_ATE_boolean:
+      type = dwarf2_fundamental_type (current_objfile, FT_BOOLEAN);
+      return type;
+    case DW_ATE_complex_float:
+      if (size == 16)
+       {
+         type = dwarf2_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX);
+       }
+      else
+       {
+         type = dwarf2_fundamental_type (current_objfile, FT_COMPLEX);
+       }
+      return type;
+    case DW_ATE_float:
+      if (size == 8)
+       {
+         type = dwarf2_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
+       }
+      else
+       {
+         type = dwarf2_fundamental_type (current_objfile, FT_FLOAT);
+       }
+      return type;
+    case DW_ATE_signed:
+      switch (size)
+       {
+       case 1:
+         type = dwarf2_fundamental_type (current_objfile, FT_SIGNED_CHAR);
+         break;
+       case 2:
+         type = dwarf2_fundamental_type (current_objfile, FT_SIGNED_SHORT);
+         break;
+       default:
+       case 4:
+         type = dwarf2_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
+         break;
+       }
+      return type;
+    case DW_ATE_signed_char:
+      type = dwarf2_fundamental_type (current_objfile, FT_SIGNED_CHAR);
+      return type;
+    case DW_ATE_unsigned:
+      switch (size)
+       {
+       case 1:
+         type = dwarf2_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+         break;
+       case 2:
+         type = dwarf2_fundamental_type (current_objfile, FT_SIGNED_SHORT);
+         break;
+       default:
+       case 4:
+         type = dwarf2_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+         break;
+       }
+      return type;
+    case DW_ATE_unsigned_char:
+      type = dwarf2_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+      return type;
+    default:
+      type = dwarf2_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
+      return type;
+    }
+}
+
+/* Given a pointer to a string and a pointer to an obstack, allocates
+   a fresh copy of the string on the specified obstack.  */
+
+static char *
+create_name (name, obstackp)
+     char *name;
+     struct obstack *obstackp;
+{
+  int length;
+  char *newname;
+
+  length = strlen (name) + 1;
+  newname = (char *) obstack_alloc (obstackp, length);
+  strcpy (newname, name);
+  return (newname);
+}
+
+struct die_info *
+copy_die (old_die)
+     struct die_info *old_die;
+{
+  struct die_info *new_die;
+  int i, num_attrs;
+
+  new_die = (struct die_info *) xmalloc (sizeof (struct die_info));
+  memset (new_die, 0, sizeof (struct die_info));
+
+  new_die->tag = old_die->tag;
+  new_die->has_children = old_die->has_children;
+  new_die->abbrev = old_die->abbrev;
+  new_die->offset = old_die->offset;
+  new_die->type = NULL;
+
+  num_attrs = old_die->num_attrs;
+  new_die->num_attrs = num_attrs;
+  new_die->attrs = (struct attribute *)
+    xmalloc (num_attrs * sizeof (struct attribute));
+
+  for (i = 0; i < old_die->num_attrs; ++i)
+    {
+      new_die->attrs[i].name = old_die->attrs[i].name;
+      new_die->attrs[i].form = old_die->attrs[i].form;
+      new_die->attrs[i].u.addr = old_die->attrs[i].u.addr;
+    }
+
+  new_die->next = NULL;
+  return new_die;
+}
+
+/* Return sibling of die, NULL if no sibling.  */
+
+struct die_info *
+sibling_die (die)
+     struct die_info *die;
+{
+  struct die_info *new;
+  int nesting_level = 0;
+
+  if (!die->has_children)
+    {
+      if (die->next && (die->next->tag == 0))
+       {
+         return NULL;
+       }
+      else
+       {
+         return die->next;
+       }
+    }
+  else
+    {
+      do
+       {
+         if (die->has_children)
+           {
+             nesting_level++;
+           }
+         if (die->tag == 0)
+           {
+             nesting_level--;
+           }
+         die = die->next;
+       }
+      while (nesting_level);
+      if (die && (die->tag == 0))
+       {
+         return NULL;
+       }
+      else
+       {
+         return die;
+       }
+    }
+}
+
+/* Convert a DIE tag into its string name.  */
+
+static char *
+dwarf_tag_name (tag)
+     register unsigned tag;
+{
+  switch (tag)
+    {
+    case DW_TAG_padding:
+      return "DW_TAG_padding";
+    case DW_TAG_array_type:
+      return "DW_TAG_array_type";
+    case DW_TAG_class_type:
+      return "DW_TAG_class_type";
+    case DW_TAG_entry_point:
+      return "DW_TAG_entry_point";
+    case DW_TAG_enumeration_type:
+      return "DW_TAG_enumeration_type";
+    case DW_TAG_formal_parameter:
+      return "DW_TAG_formal_parameter";
+    case DW_TAG_imported_declaration:
+      return "DW_TAG_imported_declaration";
+    case DW_TAG_label:
+      return "DW_TAG_label";
+    case DW_TAG_lexical_block:
+      return "DW_TAG_lexical_block";
+    case DW_TAG_member:
+      return "DW_TAG_member";
+    case DW_TAG_pointer_type:
+      return "DW_TAG_pointer_type";
+    case DW_TAG_reference_type:
+      return "DW_TAG_reference_type";
+    case DW_TAG_compile_unit:
+      return "DW_TAG_compile_unit";
+    case DW_TAG_string_type:
+      return "DW_TAG_string_type";
+    case DW_TAG_structure_type:
+      return "DW_TAG_structure_type";
+    case DW_TAG_subroutine_type:
+      return "DW_TAG_subroutine_type";
+    case DW_TAG_typedef:
+      return "DW_TAG_typedef";
+    case DW_TAG_union_type:
+      return "DW_TAG_union_type";
+    case DW_TAG_unspecified_parameters:
+      return "DW_TAG_unspecified_parameters";
+    case DW_TAG_variant:
+      return "DW_TAG_variant";
+    case DW_TAG_common_block:
+      return "DW_TAG_common_block";
+    case DW_TAG_common_inclusion:
+      return "DW_TAG_common_inclusion";
+    case DW_TAG_inheritance:
+      return "DW_TAG_inheritance";
+    case DW_TAG_inlined_subroutine:
+      return "DW_TAG_inlined_subroutine";
+    case DW_TAG_module:
+      return "DW_TAG_module";
+    case DW_TAG_ptr_to_member_type:
+      return "DW_TAG_ptr_to_member_type";
+    case DW_TAG_set_type:
+      return "DW_TAG_set_type";
+    case DW_TAG_subrange_type:
+      return "DW_TAG_subrange_type";
+    case DW_TAG_with_stmt:
+      return "DW_TAG_with_stmt";
+    case DW_TAG_access_declaration:
+      return "DW_TAG_access_declaration";
+    case DW_TAG_base_type:
+      return "DW_TAG_base_type";
+    case DW_TAG_catch_block:
+      return "DW_TAG_catch_block";
+    case DW_TAG_const_type:
+      return "DW_TAG_const_type";
+    case DW_TAG_constant:
+      return "DW_TAG_constant";
+    case DW_TAG_enumerator:
+      return "DW_TAG_enumerator";
+    case DW_TAG_file_type:
+      return "DW_TAG_file_type";
+    case DW_TAG_friend:
+      return "DW_TAG_friend";
+    case DW_TAG_namelist:
+      return "DW_TAG_namelist";
+    case DW_TAG_namelist_item:
+      return "DW_TAG_namelist_item";
+    case DW_TAG_packed_type:
+      return "DW_TAG_packed_type";
+    case DW_TAG_subprogram:
+      return "DW_TAG_subprogram";
+    case DW_TAG_template_type_param:
+      return "DW_TAG_template_type_param";
+    case DW_TAG_template_value_param:
+      return "DW_TAG_template_value_param";
+    case DW_TAG_thrown_type:
+      return "DW_TAG_thrown_type";
+    case DW_TAG_try_block:
+      return "DW_TAG_try_block";
+    case DW_TAG_variant_part:
+      return "DW_TAG_variant_part";
+    case DW_TAG_variable:
+      return "DW_TAG_variable";
+    case DW_TAG_volatile_type:
+      return "DW_TAG_volatile_type";
+    case DW_TAG_MIPS_loop:
+      return "DW_TAG_MIPS_loop";
+    case DW_TAG_format_label:
+      return "DW_TAG_format_label";
+    case DW_TAG_function_template:
+      return "DW_TAG_function_template";
+    case DW_TAG_class_template:
+      return "DW_TAG_class_template";
+    default:
+      return "DW_TAG_<unknown>";
+    }
+}
+
+/* Convert a DWARF attribute code into its string name.  */
+
+static char *
+dwarf_attr_name (attr)
+     register unsigned attr;
+{
+  switch (attr)
+    {
+    case DW_AT_sibling:
+      return "DW_AT_sibling";
+    case DW_AT_location:
+      return "DW_AT_location";
+    case DW_AT_name:
+      return "DW_AT_name";
+    case DW_AT_ordering:
+      return "DW_AT_ordering";
+    case DW_AT_subscr_data:
+      return "DW_AT_subscr_data";
+    case DW_AT_byte_size:
+      return "DW_AT_byte_size";
+    case DW_AT_bit_offset:
+      return "DW_AT_bit_offset";
+    case DW_AT_bit_size:
+      return "DW_AT_bit_size";
+    case DW_AT_element_list:
+      return "DW_AT_element_list";
+    case DW_AT_stmt_list:
+      return "DW_AT_stmt_list";
+    case DW_AT_low_pc:
+      return "DW_AT_low_pc";
+    case DW_AT_high_pc:
+      return "DW_AT_high_pc";
+    case DW_AT_language:
+      return "DW_AT_language";
+    case DW_AT_member:
+      return "DW_AT_member";
+    case DW_AT_discr:
+      return "DW_AT_discr";
+    case DW_AT_discr_value:
+      return "DW_AT_discr_value";
+    case DW_AT_visibility:
+      return "DW_AT_visibility";
+    case DW_AT_import:
+      return "DW_AT_import";
+    case DW_AT_string_length:
+      return "DW_AT_string_length";
+    case DW_AT_common_reference:
+      return "DW_AT_common_reference";
+    case DW_AT_comp_dir:
+      return "DW_AT_comp_dir";
+    case DW_AT_const_value:
+      return "DW_AT_const_value";
+    case DW_AT_containing_type:
+      return "DW_AT_containing_type";
+    case DW_AT_default_value:
+      return "DW_AT_default_value";
+    case DW_AT_inline:
+      return "DW_AT_inline";
+    case DW_AT_is_optional:
+      return "DW_AT_is_optional";
+    case DW_AT_lower_bound:
+      return "DW_AT_lower_bound";
+    case DW_AT_producer:
+      return "DW_AT_producer";
+    case DW_AT_prototyped:
+      return "DW_AT_prototyped";
+    case DW_AT_return_addr:
+      return "DW_AT_return_addr";
+    case DW_AT_start_scope:
+      return "DW_AT_start_scope";
+    case DW_AT_stride_size:
+      return "DW_AT_stride_size";
+    case DW_AT_upper_bound:
+      return "DW_AT_upper_bound";
+    case DW_AT_abstract_origin:
+      return "DW_AT_abstract_origin";
+    case DW_AT_accessibility:
+      return "DW_AT_accessibility";
+    case DW_AT_address_class:
+      return "DW_AT_address_class";
+    case DW_AT_artificial:
+      return "DW_AT_artificial";
+    case DW_AT_base_types:
+      return "DW_AT_base_types";
+    case DW_AT_calling_convention:
+      return "DW_AT_calling_convention";
+    case DW_AT_count:
+      return "DW_AT_count";
+    case DW_AT_data_member_location:
+      return "DW_AT_data_member_location";
+    case DW_AT_decl_column:
+      return "DW_AT_decl_column";
+    case DW_AT_decl_file:
+      return "DW_AT_decl_file";
+    case DW_AT_decl_line:
+      return "DW_AT_decl_line";
+    case DW_AT_declaration:
+      return "DW_AT_declaration";
+    case DW_AT_discr_list:
+      return "DW_AT_discr_list";
+    case DW_AT_encoding:
+      return "DW_AT_encoding";
+    case DW_AT_external:
+      return "DW_AT_external";
+    case DW_AT_frame_base:
+      return "DW_AT_frame_base";
+    case DW_AT_friend:
+      return "DW_AT_friend";
+    case DW_AT_identifier_case:
+      return "DW_AT_identifier_case";
+    case DW_AT_macro_info:
+      return "DW_AT_macro_info";
+    case DW_AT_namelist_items:
+      return "DW_AT_namelist_items";
+    case DW_AT_priority:
+      return "DW_AT_priority";
+    case DW_AT_segment:
+      return "DW_AT_segment";
+    case DW_AT_specification:
+      return "DW_AT_specification";
+    case DW_AT_static_link:
+      return "DW_AT_static_link";
+    case DW_AT_type:
+      return "DW_AT_type";
+    case DW_AT_use_location:
+      return "DW_AT_use_location";
+    case DW_AT_variable_parameter:
+      return "DW_AT_variable_parameter";
+    case DW_AT_virtuality:
+      return "DW_AT_virtuality";
+    case DW_AT_vtable_elem_location:
+      return "DW_AT_vtable_elem_location";
+
+#ifdef MIPS
+    case DW_AT_MIPS_fde:
+      return "DW_AT_MIPS_fde";
+    case DW_AT_MIPS_loop_begin:
+      return "DW_AT_MIPS_loop_begin";
+    case DW_AT_MIPS_tail_loop_begin:
+      return "DW_AT_MIPS_tail_loop_begin";
+    case DW_AT_MIPS_epilog_begin:
+      return "DW_AT_MIPS_epilog_begin";
+    case DW_AT_MIPS_loop_unroll_factor:
+      return "DW_AT_MIPS_loop_unroll_factor";
+    case DW_AT_MIPS_software_pipeline_depth:
+      return "DW_AT_MIPS_software_pipeline_depth";
+    case DW_AT_MIPS_linkage_name:
+      return "DW_AT_MIPS_linkage_name";
+#endif
+
+    case DW_AT_sf_names:
+      return "DW_AT_sf_names";
+    case DW_AT_src_info:
+      return "DW_AT_src_info";
+    case DW_AT_mac_info:
+      return "DW_AT_mac_info";
+    case DW_AT_src_coords:
+      return "DW_AT_src_coords";
+    case DW_AT_body_begin:
+      return "DW_AT_body_begin";
+    case DW_AT_body_end:
+      return "DW_AT_body_end";
+    default:
+      return "DW_AT_<unknown>";
+    }
+}
+
+/* Convert a DWARF value form code into its string name.  */
+
+static char *
+dwarf_form_name (form)
+     register unsigned form;
+{
+  switch (form)
+    {
+    case DW_FORM_addr:
+      return "DW_FORM_addr";
+    case DW_FORM_block2:
+      return "DW_FORM_block2";
+    case DW_FORM_block4:
+      return "DW_FORM_block4";
+    case DW_FORM_data2:
+      return "DW_FORM_data2";
+    case DW_FORM_data4:
+      return "DW_FORM_data4";
+    case DW_FORM_data8:
+      return "DW_FORM_data8";
+    case DW_FORM_string:
+      return "DW_FORM_string";
+    case DW_FORM_block:
+      return "DW_FORM_block";
+    case DW_FORM_block1:
+      return "DW_FORM_block1";
+    case DW_FORM_data1:
+      return "DW_FORM_data1";
+    case DW_FORM_flag:
+      return "DW_FORM_flag";
+    case DW_FORM_sdata:
+      return "DW_FORM_sdata";
+    case DW_FORM_strp:
+      return "DW_FORM_strp";
+    case DW_FORM_udata:
+      return "DW_FORM_udata";
+    case DW_FORM_ref_addr:
+      return "DW_FORM_ref_addr";
+    case DW_FORM_ref1:
+      return "DW_FORM_ref1";
+    case DW_FORM_ref2:
+      return "DW_FORM_ref2";
+    case DW_FORM_ref4:
+      return "DW_FORM_ref4";
+    case DW_FORM_ref8:
+      return "DW_FORM_ref8";
+    case DW_FORM_ref_udata:
+      return "DW_FORM_ref_udata";
+    case DW_FORM_indirect:
+      return "DW_FORM_indirect";
+    default:
+      return "DW_FORM_<unknown>";
+    }
+}
+
+/* Convert a DWARF stack opcode into its string name.  */
+
+static char *
+dwarf_stack_op_name (op)
+     register unsigned op;
+{
+  switch (op)
+    {
+    case DW_OP_addr:
+      return "DW_OP_addr";
+    case DW_OP_deref:
+      return "DW_OP_deref";
+    case DW_OP_const1u:
+      return "DW_OP_const1u";
+    case DW_OP_const1s:
+      return "DW_OP_const1s";
+    case DW_OP_const2u:
+      return "DW_OP_const2u";
+    case DW_OP_const2s:
+      return "DW_OP_const2s";
+    case DW_OP_const4u:
+      return "DW_OP_const4u";
+    case DW_OP_const4s:
+      return "DW_OP_const4s";
+    case DW_OP_const8u:
+      return "DW_OP_const8u";
+    case DW_OP_const8s:
+      return "DW_OP_const8s";
+    case DW_OP_constu:
+      return "DW_OP_constu";
+    case DW_OP_consts:
+      return "DW_OP_consts";
+    case DW_OP_dup:
+      return "DW_OP_dup";
+    case DW_OP_drop:
+      return "DW_OP_drop";
+    case DW_OP_over:
+      return "DW_OP_over";
+    case DW_OP_pick:
+      return "DW_OP_pick";
+    case DW_OP_swap:
+      return "DW_OP_swap";
+    case DW_OP_rot:
+      return "DW_OP_rot";
+    case DW_OP_xderef:
+      return "DW_OP_xderef";
+    case DW_OP_abs:
+      return "DW_OP_abs";
+    case DW_OP_and:
+      return "DW_OP_and";
+    case DW_OP_div:
+      return "DW_OP_div";
+    case DW_OP_minus:
+      return "DW_OP_minus";
+    case DW_OP_mod:
+      return "DW_OP_mod";
+    case DW_OP_mul:
+      return "DW_OP_mul";
+    case DW_OP_neg:
+      return "DW_OP_neg";
+    case DW_OP_not:
+      return "DW_OP_not";
+    case DW_OP_or:
+      return "DW_OP_or";
+    case DW_OP_plus:
+      return "DW_OP_plus";
+    case DW_OP_plus_uconst:
+      return "DW_OP_plus_uconst";
+    case DW_OP_shl:
+      return "DW_OP_shl";
+    case DW_OP_shr:
+      return "DW_OP_shr";
+    case DW_OP_shra:
+      return "DW_OP_shra";
+    case DW_OP_xor:
+      return "DW_OP_xor";
+    case DW_OP_bra:
+      return "DW_OP_bra";
+    case DW_OP_eq:
+      return "DW_OP_eq";
+    case DW_OP_ge:
+      return "DW_OP_ge";
+    case DW_OP_gt:
+      return "DW_OP_gt";
+    case DW_OP_le:
+      return "DW_OP_le";
+    case DW_OP_lt:
+      return "DW_OP_lt";
+    case DW_OP_ne:
+      return "DW_OP_ne";
+    case DW_OP_skip:
+      return "DW_OP_skip";
+    case DW_OP_lit0:
+      return "DW_OP_lit0";
+    case DW_OP_lit1:
+      return "DW_OP_lit1";
+    case DW_OP_lit2:
+      return "DW_OP_lit2";
+    case DW_OP_lit3:
+      return "DW_OP_lit3";
+    case DW_OP_lit4:
+      return "DW_OP_lit4";
+    case DW_OP_lit5:
+      return "DW_OP_lit5";
+    case DW_OP_lit6:
+      return "DW_OP_lit6";
+    case DW_OP_lit7:
+      return "DW_OP_lit7";
+    case DW_OP_lit8:
+      return "DW_OP_lit8";
+    case DW_OP_lit9:
+      return "DW_OP_lit9";
+    case DW_OP_lit10:
+      return "DW_OP_lit10";
+    case DW_OP_lit11:
+      return "DW_OP_lit11";
+    case DW_OP_lit12:
+      return "DW_OP_lit12";
+    case DW_OP_lit13:
+      return "DW_OP_lit13";
+    case DW_OP_lit14:
+      return "DW_OP_lit14";
+    case DW_OP_lit15:
+      return "DW_OP_lit15";
+    case DW_OP_lit16:
+      return "DW_OP_lit16";
+    case DW_OP_lit17:
+      return "DW_OP_lit17";
+    case DW_OP_lit18:
+      return "DW_OP_lit18";
+    case DW_OP_lit19:
+      return "DW_OP_lit19";
+    case DW_OP_lit20:
+      return "DW_OP_lit20";
+    case DW_OP_lit21:
+      return "DW_OP_lit21";
+    case DW_OP_lit22:
+      return "DW_OP_lit22";
+    case DW_OP_lit23:
+      return "DW_OP_lit23";
+    case DW_OP_lit24:
+      return "DW_OP_lit24";
+    case DW_OP_lit25:
+      return "DW_OP_lit25";
+    case DW_OP_lit26:
+      return "DW_OP_lit26";
+    case DW_OP_lit27:
+      return "DW_OP_lit27";
+    case DW_OP_lit28:
+      return "DW_OP_lit28";
+    case DW_OP_lit29:
+      return "DW_OP_lit29";
+    case DW_OP_lit30:
+      return "DW_OP_lit30";
+    case DW_OP_lit31:
+      return "DW_OP_lit31";
+    case DW_OP_reg0:
+      return "DW_OP_reg0";
+    case DW_OP_reg1:
+      return "DW_OP_reg1";
+    case DW_OP_reg2:
+      return "DW_OP_reg2";
+    case DW_OP_reg3:
+      return "DW_OP_reg3";
+    case DW_OP_reg4:
+      return "DW_OP_reg4";
+    case DW_OP_reg5:
+      return "DW_OP_reg5";
+    case DW_OP_reg6:
+      return "DW_OP_reg6";
+    case DW_OP_reg7:
+      return "DW_OP_reg7";
+    case DW_OP_reg8:
+      return "DW_OP_reg8";
+    case DW_OP_reg9:
+      return "DW_OP_reg9";
+    case DW_OP_reg10:
+      return "DW_OP_reg10";
+    case DW_OP_reg11:
+      return "DW_OP_reg11";
+    case DW_OP_reg12:
+      return "DW_OP_reg12";
+    case DW_OP_reg13:
+      return "DW_OP_reg13";
+    case DW_OP_reg14:
+      return "DW_OP_reg14";
+    case DW_OP_reg15:
+      return "DW_OP_reg15";
+    case DW_OP_reg16:
+      return "DW_OP_reg16";
+    case DW_OP_reg17:
+      return "DW_OP_reg17";
+    case DW_OP_reg18:
+      return "DW_OP_reg18";
+    case DW_OP_reg19:
+      return "DW_OP_reg19";
+    case DW_OP_reg20:
+      return "DW_OP_reg20";
+    case DW_OP_reg21:
+      return "DW_OP_reg21";
+    case DW_OP_reg22:
+      return "DW_OP_reg22";
+    case DW_OP_reg23:
+      return "DW_OP_reg23";
+    case DW_OP_reg24:
+      return "DW_OP_reg24";
+    case DW_OP_reg25:
+      return "DW_OP_reg25";
+    case DW_OP_reg26:
+      return "DW_OP_reg26";
+    case DW_OP_reg27:
+      return "DW_OP_reg27";
+    case DW_OP_reg28:
+      return "DW_OP_reg28";
+    case DW_OP_reg29:
+      return "DW_OP_reg29";
+    case DW_OP_reg30:
+      return "DW_OP_reg30";
+    case DW_OP_reg31:
+      return "DW_OP_reg31";
+    case DW_OP_breg0:
+      return "DW_OP_breg0";
+    case DW_OP_breg1:
+      return "DW_OP_breg1";
+    case DW_OP_breg2:
+      return "DW_OP_breg2";
+    case DW_OP_breg3:
+      return "DW_OP_breg3";
+    case DW_OP_breg4:
+      return "DW_OP_breg4";
+    case DW_OP_breg5:
+      return "DW_OP_breg5";
+    case DW_OP_breg6:
+      return "DW_OP_breg6";
+    case DW_OP_breg7:
+      return "DW_OP_breg7";
+    case DW_OP_breg8:
+      return "DW_OP_breg8";
+    case DW_OP_breg9:
+      return "DW_OP_breg9";
+    case DW_OP_breg10:
+      return "DW_OP_breg10";
+    case DW_OP_breg11:
+      return "DW_OP_breg11";
+    case DW_OP_breg12:
+      return "DW_OP_breg12";
+    case DW_OP_breg13:
+      return "DW_OP_breg13";
+    case DW_OP_breg14:
+      return "DW_OP_breg14";
+    case DW_OP_breg15:
+      return "DW_OP_breg15";
+    case DW_OP_breg16:
+      return "DW_OP_breg16";
+    case DW_OP_breg17:
+      return "DW_OP_breg17";
+    case DW_OP_breg18:
+      return "DW_OP_breg18";
+    case DW_OP_breg19:
+      return "DW_OP_breg19";
+    case DW_OP_breg20:
+      return "DW_OP_breg20";
+    case DW_OP_breg21:
+      return "DW_OP_breg21";
+    case DW_OP_breg22:
+      return "DW_OP_breg22";
+    case DW_OP_breg23:
+      return "DW_OP_breg23";
+    case DW_OP_breg24:
+      return "DW_OP_breg24";
+    case DW_OP_breg25:
+      return "DW_OP_breg25";
+    case DW_OP_breg26:
+      return "DW_OP_breg26";
+    case DW_OP_breg27:
+      return "DW_OP_breg27";
+    case DW_OP_breg28:
+      return "DW_OP_breg28";
+    case DW_OP_breg29:
+      return "DW_OP_breg29";
+    case DW_OP_breg30:
+      return "DW_OP_breg30";
+    case DW_OP_breg31:
+      return "DW_OP_breg31";
+    case DW_OP_regx:
+      return "DW_OP_regx";
+    case DW_OP_fbreg:
+      return "DW_OP_fbreg";
+    case DW_OP_bregx:
+      return "DW_OP_bregx";
+    case DW_OP_piece:
+      return "DW_OP_piece";
+    case DW_OP_deref_size:
+      return "DW_OP_deref_size";
+    case DW_OP_xderef_size:
+      return "DW_OP_xderef_size";
+    case DW_OP_nop:
+      return "DW_OP_nop";
+    default:
+      return "OP_<unknown>";
+    }
+}
+
+static char *
+dwarf_bool_name (bool)
+     unsigned bool;
+{
+  if (bool)
+    return "TRUE";
+  else
+    return "FALSE";
+}
+
+/* Convert a DWARF type code into its string name.  */
+
+static char *
+dwarf_type_encoding_name (enc)
+     register unsigned enc;
+{
+  switch (enc)
+    {
+    case DW_ATE_address:
+      return "DW_ATE_address";
+    case DW_ATE_boolean:
+      return "DW_ATE_boolean";
+    case DW_ATE_complex_float:
+      return "DW_ATE_complex_float";
+    case DW_ATE_float:
+      return "DW_ATE_float";
+    case DW_ATE_signed:
+      return "DW_ATE_signed";
+    case DW_ATE_signed_char:
+      return "DW_ATE_signed_char";
+    case DW_ATE_unsigned:
+      return "DW_ATE_unsigned";
+    case DW_ATE_unsigned_char:
+      return "DW_ATE_unsigned_char";
+    default:
+      return "DW_ATE_<unknown>";
+    }
+}
+
+/* Convert a DWARF call frame info operation to its string name. */
+
+static char *
+dwarf_cfi_name (cfi_opc)
+     register unsigned cfi_opc;
+{
+  switch (cfi_opc)
+    {
+    case DW_CFA_advance_loc:
+      return "DW_CFA_advance_loc";
+    case DW_CFA_offset:
+      return "DW_CFA_offset";
+    case DW_CFA_restore:
+      return "DW_CFA_restore";
+    case DW_CFA_nop:
+      return "DW_CFA_nop";
+    case DW_CFA_set_loc:
+      return "DW_CFA_set_loc";
+    case DW_CFA_advance_loc1:
+      return "DW_CFA_advance_loc1";
+    case DW_CFA_advance_loc2:
+      return "DW_CFA_advance_loc2";
+    case DW_CFA_advance_loc4:
+      return "DW_CFA_advance_loc4";
+    case DW_CFA_offset_extended:
+      return "DW_CFA_offset_extended";
+    case DW_CFA_restore_extended:
+      return "DW_CFA_restore_extended";
+    case DW_CFA_undefined:
+      return "DW_CFA_undefined";
+    case DW_CFA_same_value:
+      return "DW_CFA_same_value";
+    case DW_CFA_register:
+      return "DW_CFA_register";
+    case DW_CFA_remember_state:
+      return "DW_CFA_remember_state";
+    case DW_CFA_restore_state:
+      return "DW_CFA_restore_state";
+    case DW_CFA_def_cfa:
+      return "DW_CFA_def_cfa";
+    case DW_CFA_def_cfa_register:
+      return "DW_CFA_def_cfa_register";
+    case DW_CFA_def_cfa_offset:
+      return "DW_CFA_def_cfa_offset";
+      /* SGI/MIPS specific */
+    case DW_CFA_MIPS_advance_loc8:
+      return "DW_CFA_MIPS_advance_loc8";
+    default:
+      return "DW_CFA_<unknown>";
+    }
+}
+
+void
+dump_die (die)
+     struct die_info *die;
+{
+  int i;
+
+  fprintf (stderr, "Die: %s (abbrev = %d, offset = %d)\n",
+          dwarf_tag_name (die->tag), die->abbrev, die->offset);
+  fprintf (stderr, "\thas children: %s\n",
+          dwarf_bool_name (die->has_children));
+
+  fprintf (stderr, "\tattributes:\n");
+  for (i = 0; i < die->num_attrs; ++i)
+    {
+      fprintf (stderr, "\t\t%s (%s) ",
+              dwarf_attr_name (die->attrs[i].name),
+              dwarf_form_name (die->attrs[i].form));
+      switch (die->attrs[i].form)
+       {
+       case DW_FORM_ref_addr:
+       case DW_FORM_addr:
+         fprintf (stderr, sizeof (CORE_ADDR) > sizeof (long) ?
+                  "address: 0x%LLx" : "address: 0x%x",
+                  die->attrs[i].u.addr);
+         break;
+       case DW_FORM_block2:
+       case DW_FORM_block4:
+       case DW_FORM_block:
+       case DW_FORM_block1:
+         fprintf (stderr, "block: size %d",
+                  die->attrs[i].u.blk->size);
+         break;
+       case DW_FORM_data1:
+       case DW_FORM_data2:
+       case DW_FORM_data4:
+       case DW_FORM_ref1:
+       case DW_FORM_ref2:
+       case DW_FORM_ref4:
+       case DW_FORM_udata:
+       case DW_FORM_sdata:
+         fprintf (stderr, "constant: %d", die->attrs[i].u.unsnd);
+         break;
+       case DW_FORM_string:
+         fprintf (stderr, "string: \"%s\"", die->attrs[i].u.str);
+         break;
+       case DW_FORM_flag:
+         if (die->attrs[i].u.unsnd)
+           fprintf (stderr, "flag: TRUE");
+         else
+           fprintf (stderr, "flag: FALSE");
+         break;
+       case DW_FORM_strp:      /* we do not support separate string
+                                  section yet */
+       case DW_FORM_indirect:  /* we do not handle indirect yet */
+       case DW_FORM_data8:     /* we do not have 64 bit quantities */
+         error ("Dwarf Error: Unsupported attribute form: %d.",
+                die->attrs[i].form);
+       }
+      fprintf (stderr, "\n");
+    }
+}
+
+void
+dump_die_list (die)
+     struct die_info *die;
+{
+  while (die)
+    {
+      dump_die (die);
+      die = die->next;
+    }
+}
+
+void
+store_in_ref_table (offset, die)
+     unsigned int offset;
+     struct die_info *die;
+{
+  int h;
+  struct die_info *old;
+
+  h = (offset % REF_HASH_SIZE);
+  old = die_ref_table[h];
+  die->next_ref = old;
+  die_ref_table[h] = die;
+}
+
+struct die_info *
+follow_die_ref (offset)
+     unsigned int offset;
+{
+  struct die_info *die;
+  int h;
+
+  h = (offset % REF_HASH_SIZE);
+  die = die_ref_table[h];
+  while (die)
+    {
+      if (die->offset == offset)
+       {
+         return die;
+       }
+      die = die->next_ref;
+    }
+  return NULL;
+}
+
+static struct type *
+dwarf2_fundamental_type (objfile, typeid)
+     struct objfile *objfile;
+     int typeid;
+{
+  if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
+    {
+      error ("Dwarf 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]);
+}
+
+/* Decode simple location descriptions.
+   There are three cases:
+       An address: return the address.
+       An address relative to frame pointer: return the offset.
+       A register: return register number and set isreg to true.
+       A constant followed by plus: return the constant.  */
+
+static CORE_ADDR
+decode_locdesc (blk, objfile)
+     struct dwarf_block *blk;
+     struct objfile *objfile;
+{
+  int i, snd;
+  int size = blk->size;
+  char *data = blk->data;
+  unsigned int bytes_read, unsnd;
+  unsigned char op;
+  union
+    {
+      CORE_ADDR addr;
+      char bytes[sizeof (CORE_ADDR)];
+    }
+  u;
+
+  i = 0;
+  isreg = 0;
+  offreg = 0;
+
+  /* FIXME: handle more general forms of location descriptors.  */
+  while (i < size)
+    {
+      op = data[i++];
+      switch (op)
+       {
+       case DW_OP_reg0:
+         isreg = 1;
+         return 0;
+       case DW_OP_reg1:
+         isreg = 1;
+         return 1;
+       case DW_OP_reg2:
+         isreg = 1;
+         return 2;
+       case DW_OP_reg3:
+         isreg = 1;
+         return 3;
+       case DW_OP_reg4:
+         isreg = 1;
+         return 4;
+       case DW_OP_reg5:
+         isreg = 1;
+         return 5;
+       case DW_OP_reg6:
+         isreg = 1;
+         return 6;
+       case DW_OP_reg7:
+         isreg = 1;
+         return 7;
+       case DW_OP_reg8:
+         isreg = 1;
+         return 8;
+       case DW_OP_reg9:
+         isreg = 1;
+         return 9;
+       case DW_OP_reg10:
+         isreg = 1;
+         return 10;
+       case DW_OP_reg11:
+         isreg = 1;
+         return 11;
+       case DW_OP_reg12:
+         isreg = 1;
+         return 12;
+       case DW_OP_reg13:
+         isreg = 1;
+         return 13;
+       case DW_OP_reg14:
+         isreg = 1;
+         return 14;
+       case DW_OP_reg15:
+         isreg = 1;
+         return 15;
+       case DW_OP_reg16:
+         isreg = 1;
+         return 16;
+       case DW_OP_reg17:
+         isreg = 1;
+         return 17;
+       case DW_OP_reg18:
+         isreg = 1;
+         return 18;
+       case DW_OP_reg19:
+         isreg = 1;
+         return 19;
+       case DW_OP_reg20:
+         isreg = 1;
+         return 20;
+       case DW_OP_reg21:
+         isreg = 1;
+         return 21;
+       case DW_OP_reg22:
+         isreg = 1;
+         return 22;
+       case DW_OP_reg23:
+         isreg = 1;
+         return 23;
+       case DW_OP_reg24:
+         isreg = 1;
+         return 24;
+       case DW_OP_reg25:
+         isreg = 1;
+         return 25;
+       case DW_OP_reg26:
+         isreg = 1;
+         return 26;
+       case DW_OP_reg27:
+         isreg = 1;
+         return 27;
+       case DW_OP_reg28:
+         isreg = 1;
+         return 28;
+       case DW_OP_reg29:
+         isreg = 1;
+         return 29;
+       case DW_OP_reg30:
+         isreg = 1;
+         return 30;
+       case DW_OP_reg31:
+         isreg = 1;
+         return 31;
+
+       case DW_OP_regx:
+         isreg = 1;
+         unsnd = read_unsigned_leb128 (NULL, (data + i), &bytes_read);
+         i += bytes_read;
+#if defined(HARRIS_TARGET) && defined(_M88K)
+         /* The Harris 88110 gdb ports have long kept their special reg
+            numbers between their gp-regs and their x-regs.  This is
+            not how our dwarf is generated.  Punt. */
+         return unsnd + 6;
+#else
+         return unsnd;
+#endif
+
+       case DW_OP_fbreg:
+       case DW_OP_breg31:
+         offreg = 1;
+         snd = read_signed_leb128 (NULL, (data + i), &bytes_read);
+         i += bytes_read;
+         return snd;
+
+       case DW_OP_addr:
+         isreg = 0;
+         return read_address (objfile->obfd, &data[i]);
+
+       case DW_OP_constu:
+         unsnd = read_unsigned_leb128 (NULL, (data + i), &bytes_read);
+         i += bytes_read;
+         break;
+
+       case DW_OP_plus:
+         return unsnd;
+
+       }
+    }
+  return 0;
+}
+
+/* memory allocation interface */
+
+static struct type *
+dwarf_alloc_type (objfile)
+     struct objfile *objfile;
+{
+  struct type *type;
+
+  type = (struct type *) xmalloc (sizeof (struct type));
+  memset (type, 0, sizeof (struct type));
+
+#if 0
+  type = alloc_type (objfile);
+#endif
+
+  return (type);
+}
+
+static struct abbrev_info *
+dwarf_alloc_abbrev ()
+{
+  struct abbrev_info *abbrev;
+
+  abbrev = xmalloc (sizeof (struct abbrev_info));
+  memset (abbrev, 0, sizeof (struct abbrev_info));
+  return (abbrev);
+}
+
+static struct dwarf_block *
+dwarf_alloc_block ()
+{
+  struct dwarf_block *blk;
+
+  blk = (struct dwarf_block *) xmalloc (sizeof (struct dwarf_block));
+  return (blk);
+}
+
+static struct die_info *
+dwarf_alloc_die ()
+{
+  struct die_info *die;
+
+  die = (struct die_info *) xmalloc (sizeof (struct die_info));
+  memset (die, 0, sizeof (struct die_info));
+  return (die);
+}
index 8a757e4..107bdaf 100644 (file)
@@ -407,6 +407,17 @@ elf_symtab_read (abfd, addr, objfile, dynamic)
                       should be harmless (but I encourage people to fix this
                       in the assembler instead of adding checks here).  */
                    continue;
+#ifdef HARRIS_TARGET
+                 else if (sym->name[0] == '.' && sym->name[1] == '.')
+                   {
+                     /* Looks like a Harris compiler generated label for the
+                        purpose of marking instructions that are relevant to
+                        DWARF dies.  The assembler can't get rid of these 
+                        because they are relocatable addresses that the
+                        linker needs to resolve. */
+                     continue;
+                   }
+#endif   
                  else
                    {
                      ms_type = mst_file_text;
@@ -592,7 +603,12 @@ elf_symfile_read (objfile, section_offsets, mainline)
      special ELF sections.  We first have to find them... */
 
   bfd_map_over_sections (abfd, elf_locate_sections, (PTR) &ei);
-  if (ei.dboffset && ei.lnoffset)
+  if (dwarf2_has_info (abfd) && !offset)
+    {
+      /* DWARF 2 sections */
+      dwarf2_build_psymtabs (objfile, section_offsets, mainline);
+    }
+  else if (ei.dboffset && ei.lnoffset)
     {
       /* DWARF sections */
       dwarf_build_psymtabs (objfile,
index 5921cbb..80a9927 100644 (file)
@@ -205,6 +205,13 @@ extern void
 dwarf_build_psymtabs PARAMS ((struct objfile *, struct section_offsets *, int,
                              file_ptr, unsigned int, file_ptr, unsigned int));
 
+/* From dwarf2read.c */
+
+extern int dwarf2_has_info PARAMS ((bfd *abfd));
+
+extern void dwarf2_build_psymtabs PARAMS ((struct objfile *,
+                                          struct section_offsets *,
+                                          int));
 /* From mdebugread.c */
 
 /* Hack to force structures to exist before use in parameter list.  */