OSDN Git Service

(gen_variable_dir): Add test for DW_AT_declaration to
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 886c218..c30785f 100644 (file)
@@ -1,7 +1,8 @@
 /* Output Dwarf2 format symbol table information from the GNU C compiler.
-   Copyright (C) 1992, 1993, 1995, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
    Contributed by Gary Funck (gary@intrepid.com).  Derived from the
    DWARF 1 implementation written by Ron Guilmette (rfg@monkeys.com).
+   Extensively modified by Jason Merrill (jason@cygnus.com).
 
 This file is part of GNU CC.
 
@@ -21,9 +22,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "config.h"
 
-#if defined(DWARF_DEBUGGING_INFO) && defined(DWARF_VERSION) \
-    && DWARF_VERSION == 2
+#ifdef DWARF2_DEBUGGING_INFO
 #include <stdio.h>
+#include <setjmp.h>
 #include "dwarf2.h"
 #include "tree.h"
 #include "flags.h"
@@ -34,42 +35,21 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "reload.h"
 #include "output.h"
 #include "defaults.h"
+#include "expr.h"
 
 /* #define NDEBUG 1 */
 #include "assert.h"
-#if defined(DWARF_TIMESTAMPS)
-#if defined(POSIX)
-#include <time.h>
-#else /* !defined(POSIX) */
-#include <sys/types.h>
-#if defined(__STDC__)
-extern time_t time (time_t *);
-#else /* !defined(__STDC__) */
-extern time_t time ();
-#endif /* !defined(__STDC__) */
-#endif /* !defined(POSIX) */
-#endif /* defined(DWARF_TIMESTAMPS) */
 
 extern char *getpwd ();
-extern char *index ();
-extern char *rindex ();
-
-/* IMPORTANT NOTE: Please see the file README.DWARF for important details
-   regarding the GNU implementation of DWARF.  */
 
 /* NOTE: In the comments in this file, many references are made to
    "Debugging Information Entries".  This term is abbreviated as `DIE'
    throughout the remainder of this file.  */
 
-/* NOTE: The implementation of C++ support is unfinished.  */
-
-#if defined(__GNUC__) && (NDEBUG == 1)
-#define inline static inline
-#else
-#define inline static
+#ifndef __GNUC__
+#define inline
 #endif
 
-
 /* An internal representation of the DWARF output is built, and then
    walked to generate the DWARF debugging info.  The walk of the internal
    representation is done after the entire program has been compiled.
@@ -77,185 +57,220 @@ extern char *rindex ();
 
 /* Each DIE may have a series of attribute/value pairs.  Values
    can take on several forms.  The forms that are used in this
-   impelementation are listed below.  */
+   implementation are listed below.  */
+
 typedef enum
-  {
-    dw_val_class_addr,
-    dw_val_class_loc,
-    dw_val_class_const,
-    dw_val_class_unsigned_const,
-    dw_val_class_double_const,
-    dw_val_class_flag,
-    dw_val_class_die_ref,
-    dw_val_class_fde_ref,
-    dw_val_class_lbl_id,
-    dw_val_class_section_offset,
-    dw_val_class_str
-  }
+{
+  dw_val_class_addr,
+  dw_val_class_loc,
+  dw_val_class_const,
+  dw_val_class_unsigned_const,
+  dw_val_class_long_long,
+  dw_val_class_float,
+  dw_val_class_flag,
+  dw_val_class_die_ref,
+  dw_val_class_fde_ref,
+  dw_val_class_lbl_id,
+  dw_val_class_section_offset,
+  dw_val_class_str
+}
 dw_val_class;
 
 /* Various DIE's use offsets relative to the beginning of the
    .debug_info section to refer to each other.  */
+
 typedef long int dw_offset;
 
 /* Define typedefs here to avoid circular dependencies.  */
+
 typedef struct die_struct *dw_die_ref;
 typedef struct dw_attr_struct *dw_attr_ref;
 typedef struct dw_val_struct *dw_val_ref;
 typedef struct dw_line_info_struct *dw_line_info_ref;
+typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
 typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
 typedef struct dw_cfi_struct *dw_cfi_ref;
 typedef struct dw_fde_struct *dw_fde_ref;
 typedef union  dw_cfi_oprnd_struct *dw_cfi_oprnd_ref;
-typedef struct backchain *backchain_ref;
+typedef struct pubname_struct *pubname_ref;
+typedef dw_die_ref *arange_ref;
 
 /* Describe a double word constant value.  */
-typedef struct dw_double_const_struct
-  {
-    unsigned long dw_dbl_hi;
-    unsigned long dw_dbl_low;
-  }
-dw_dbl_const;
+
+typedef struct dw_long_long_struct
+{
+  unsigned long hi;
+  unsigned long low;
+}
+dw_long_long_const;
+
+/* Describe a floating point constant value.  */
+
+typedef struct dw_fp_struct
+{
+  long *array;
+  unsigned length;
+}
+dw_float_const;
 
 /* Each entry in the line_info_table maintains the file and
    line nuber associated with the label generated for that
    entry.  The label gives the PC value associated with
    the line number entry.  */
+
 typedef struct dw_line_info_struct
-  {
-    unsigned long dw_file_num;
-    unsigned long dw_line_num;
-  }
+{
+  unsigned long dw_file_num;
+  unsigned long dw_line_num;
+}
 dw_line_info_entry;
 
+/* Line information for functions in separate sections; each one gets its
+   own sequence.  */
+typedef struct dw_separate_line_info_struct
+{
+  unsigned long dw_file_num;
+  unsigned long dw_line_num;
+  unsigned long function;
+}
+dw_separate_line_info_entry;
+
 /* The dw_val_node describes an attibute's value, as it is
-   represnted internally.  */
+   represented internally.  */
+
 typedef struct dw_val_struct
-  {
-    dw_val_class val_class;
-    union
-      {
-       char *val_addr;
-       dw_loc_descr_ref val_loc;
-       long int val_int;
-       long unsigned val_unsigned;
-       dw_dbl_const val_dbl_const;
-       dw_die_ref val_die_ref;
-       unsigned val_fde_index;
-       char *val_str;
-       char *val_lbl_id;
-       char *val_section;
-       unsigned char val_flag;
-      }
-    v;
-  }
+{
+  dw_val_class val_class;
+  union
+    {
+      char *val_addr;
+      dw_loc_descr_ref val_loc;
+      long int val_int;
+      long unsigned val_unsigned;
+      dw_long_long_const val_long_long;
+      dw_float_const val_float;
+      dw_die_ref val_die_ref;
+      unsigned val_fde_index;
+      char *val_str;
+      char *val_lbl_id;
+      char *val_section;
+      unsigned char val_flag;
+    }
+  v;
+}
 dw_val_node;
 
 /* Locations in memory are described using a sequence of stack machine
    operations.  */
+
 typedef struct dw_loc_descr_struct
-  {
-    dw_loc_descr_ref dw_loc_next;
-    enum dwarf_location_atom dw_loc_opc;
-    dw_val_node dw_loc_oprnd1;
-    dw_val_node dw_loc_oprnd2;
-  }
+{
+  dw_loc_descr_ref dw_loc_next;
+  enum dwarf_location_atom dw_loc_opc;
+  dw_val_node dw_loc_oprnd1;
+  dw_val_node dw_loc_oprnd2;
+}
 dw_loc_descr_node;
 
 /* Each DIE attribute has a field specifying the attribute kind,
    a link to the next attribute in the chain, and an attribute value.
    Attributes are typically linked below the DIE they modify.  */
+
 typedef struct dw_attr_struct
-  {
-    enum dwarf_attribute dw_attr;
-    dw_attr_ref dw_attr_next;
-    dw_val_node dw_attr_val;
-  }
+{
+  enum dwarf_attribute dw_attr;
+  dw_attr_ref dw_attr_next;
+  dw_val_node dw_attr_val;
+}
 dw_attr_node;
 
 /* Call frames are described using a sequence of Call Frame
    Information instructions.  The register number, offset
    and address fields are provided as possible operands;
    their use is selected by the opcode field.  */
+
 typedef union dw_cfi_oprnd_struct
-  {
-    unsigned long dw_cfi_reg_num;
-    long int dw_cfi_offset;
-    char *dw_cfi_addr;
-  }
+{
+  unsigned long dw_cfi_reg_num;
+  long int dw_cfi_offset;
+  char *dw_cfi_addr;
+}
 dw_cfi_oprnd;
 
 typedef struct dw_cfi_struct
-  {
-    dw_cfi_ref dw_cfi_next;
-    enum dwarf_call_frame_info dw_cfi_opc;
-    dw_cfi_oprnd dw_cfi_oprnd1;
-    dw_cfi_oprnd dw_cfi_oprnd2;
-  }
+{
+  dw_cfi_ref dw_cfi_next;
+  enum dwarf_call_frame_info dw_cfi_opc;
+  dw_cfi_oprnd dw_cfi_oprnd1;
+  dw_cfi_oprnd dw_cfi_oprnd2;
+}
 dw_cfi_node;
 
 /* All call frame descriptions (FDE's) in the GCC generated DWARF
-   refer to a signle Common Information Entry (CIE), defined at
+   refer to a single Common Information Entry (CIE), defined at
    the beginning of the .debug_frame section.  This used of a single
    CIE obviates the need to keep track of multiple CIE's
    in the DWARF generation routines below.  */
+
 typedef struct dw_fde_struct
-  {
-    unsigned long dw_fde_offset;
-    char *dw_fde_begin;
-    char *dw_fde_end_prolog;
-    char *dw_fde_begin_epilogue;
-    char *dw_fde_end;
-    dw_cfi_ref dw_fde_cfi;
-  }
+{
+  unsigned long dw_fde_offset;
+  char *dw_fde_begin;
+  char *dw_fde_current_label;
+  char *dw_fde_end;
+  dw_cfi_ref dw_fde_cfi;
+}
 dw_fde_node;
 
 /* The Debugging Information Entry (DIE) structure */
+
 typedef struct die_struct
-  {
-    enum dwarf_tag die_tag;
-    dw_attr_ref die_attr;
-    dw_attr_ref die_attr_last;
-    dw_die_ref die_parent;
-    dw_die_ref die_child;
-    dw_die_ref die_child_last;
-    dw_die_ref die_sib;
-    dw_offset die_offset;
-    unsigned long die_abbrev;
-  }
+{
+  enum dwarf_tag die_tag;
+  dw_attr_ref die_attr;
+  dw_attr_ref die_attr_last;
+  dw_die_ref die_parent;
+  dw_die_ref die_child;
+  dw_die_ref die_child_last;
+  dw_die_ref die_sib;
+  dw_offset die_offset;
+  unsigned long die_abbrev;
+}
 die_node;
 
-/* The structure for backchaining support, when structure tags are declared
-   before they are defined.  */
+/* The pubname structure */
 
-typedef struct backchain
-  {
-    tree type;
-    dw_die_ref placeholder;
-    backchain_ref next;
-  }
-backchain_t;
+typedef struct pubname_struct
+{
+  dw_die_ref die;
+  char * name;
+}
+pubname_entry;
 
 /* How to start an assembler comment.  */
 #ifndef ASM_COMMENT_START
 #define ASM_COMMENT_START ";#"
 #endif
 
-/* Define a macro which returns non-zero for any tagged type which is used
-   (directly or indirectly) in the specification of either some function's
-   return type or some formal parameter of some function. We use this macro
-   when we are operating in "terse" mode to help us know what tagged types
-   have to be represented in Dwarf (even in terse mode) and which ones don't.
-   A flag bit with this meaning really should be a part of the normal GCC
-   ..._TYPE nodes, but at the moment, there is no such bit defined for these
-   nodes.  For now, we have to just fake it.  It it safe for us to simply
-   return zero for all complete tagged types (which will get forced out
-   anyway if they were used in the specification of some formal or return
-   type) and non-zero for all incomplete tagged types.  */
-#define TYPE_USED_FOR_FUNCTION(tagged_type) (TYPE_SIZE (tagged_type) == 0)
+/* Define a macro which returns non-zero for a TYPE_DECL which was
+   implicitly generated for a tagged type.
+
+   Note that unlike the gcc front end (which generates a NULL named
+   TYPE_DECL node for each complete tagged type, each array type, and
+   each function type node created) the g++ front end generates a
+   _named_ TYPE_DECL node for each tagged type node created.
+   These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to
+   generate a DW_TAG_typedef DIE for them.  */
+
+#define TYPE_DECL_IS_STUB(decl)                                \
+  (DECL_NAME (decl) == NULL_TREE                       \
+   || (DECL_ARTIFICIAL (decl)                          \
+       && is_tagged_type (TREE_TYPE (decl))            \
+       && decl == TYPE_STUB_DECL (TREE_TYPE (decl))))
 
 /* Information concerning the compilation unit's programming
    language, and compiler version.  */
+
 extern int flag_traditional;
 extern char *version_string;
 extern char *language_string;
@@ -267,65 +282,57 @@ extern char *language_string;
    are only defaults.  If the sizes are different for your target, you should
    override these values by defining the appropriate symbols in your tm.h
    file.  */
+
 #ifndef CHAR_TYPE_SIZE
 #define CHAR_TYPE_SIZE BITS_PER_UNIT
 #endif
-#ifndef SHORT_TYPE_SIZE
-#define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2)
-#endif
-#ifndef INT_TYPE_SIZE
-#define INT_TYPE_SIZE BITS_PER_WORD
-#endif
-#ifndef LONG_TYPE_SIZE
-#define LONG_TYPE_SIZE BITS_PER_WORD
-#endif
-#ifndef LONG_LONG_TYPE_SIZE
-#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-#ifndef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
-#endif
-#ifndef WCHAR_UNSIGNED
-#define WCHAR_UNSIGNED 0
-#endif
-#ifndef FLOAT_TYPE_SIZE
-#define FLOAT_TYPE_SIZE BITS_PER_WORD
-#endif
-#ifndef DOUBLE_TYPE_SIZE
-#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-#ifndef LONG_DOUBLE_TYPE_SIZE
-#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
 #ifndef PTR_SIZE
-#define PTR_SIZE (POINTER_SIZE / 8)
+#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
+#endif
+
+/* The size in bytes of a DWARF field indicating an offset or length
+   relative to a debug info section, specified to be 4 bytes in the DWARF-2
+   specification.  The SGI/MIPS ABI defines it to be the same as PTR_SIZE.  */
+
+#ifndef DWARF_OFFSET_SIZE
+#define DWARF_OFFSET_SIZE 4
 #endif
 
+#define DWARF_VERSION 2
+
 /* Fixed size portion of the DWARF compilation unit header.  */
-#define DWARF_COMPILE_UNIT_HEADER_SIZE 11
+#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3)
 
 /* Fixed size portion of debugging line information prolog.  */
 #define DWARF_LINE_PROLOG_HEADER_SIZE 5
 
 /* Fixed size portion of public names info.  */
-#define DWARF_PUBNAMES_HEADER_SIZE 10
+#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
+
+/* Round SIZE up to the nearest BOUNDARY.  */
+#define DWARF_ROUND(SIZE,BOUNDARY) \
+  (((SIZE) + (BOUNDARY) - 1) & ~((BOUNDARY) - 1))
 
 /* Fixed size portion of the address range info.  */
-#define DWARF_ARANGES_HEADER_SIZE 12
+#define DWARF_ARANGES_HEADER_SIZE \
+  (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE)
 
-/* Fixed size portion of the Common Information Entry (including
-   the length field).  */
-#define DWARF_CIE_HEADER_SIZE 16
+/* Fixed size portion of the CIE (including the length field).  */
+#define DWARF_CIE_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 5)
 
-/* Fixed size of the Common Information Entry in the call frame
-   information (.debug_frame) section rounded up to an 8 byte boundary.  */
-#define DWARF_CIE_SIZE ((DWARF_CIE_HEADER_SIZE + 7) & ~7)
+/* The un-padded size of the CIE.  Initialized in calc_fde_sizes, used
+   in output_call_frame_info.  */
+static unsigned cie_size;
 
 /* Offsets recorded in opcodes are a multiple of this alignment factor.  */
-#define DWARF_CIE_DATA_ALIGNMENT -4
+#ifdef STACK_GROWS_DOWNWARD
+#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_WORD)
+#else
+#define DWARF_CIE_DATA_ALIGNMENT UNITS_PER_WORD
+#endif
 
 /* Fixed size portion of the FDE.  */
-#define DWARF_FDE_HEADER_SIZE (4 + 4 + (2 * PTR_SIZE))
+#define DWARF_FDE_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2 * PTR_SIZE)
 
 /* Define the architecture-dependent minimum instruction length (in bytes).
    In this implementation of DWARF, this field is used for information
@@ -333,6 +340,7 @@ extern char *language_string;
    no a priori knowledge of how many instruction bytes are generated
    for each source line, and therefore can use only the  DW_LNE_set_address
    and DW_LNS_fixed_advance_pc line information commands.  */
+
 #ifndef DWARF_LINE_MIN_INSTR_LENGTH
 #define DWARF_LINE_MIN_INSTR_LENGTH 4
 #endif
@@ -362,7 +370,10 @@ static unsigned long next_die_offset;
 static unsigned long next_fde_offset;
 
 /* Record the root of the DIE's built for the current compilation unit.  */
-dw_die_ref comp_unit_die;
+static dw_die_ref comp_unit_die;
+
+/* The number of DIEs with a NULL parent waiting to be relocated.  */
+static int limbo_die_count;
 
 /* Pointer to an array of filenames referenced by this compilation unit.  */
 static char **file_table;
@@ -380,7 +391,7 @@ static unsigned file_table_in_use;
 #define FILE_TABLE_INCREMENT 64
 
 /* Local pointer to the name of the main input file.  Initialized in
-   dwarfout_init.  */
+   dwarf2out_init.  */
 static char *primary_filename;
 
 /* For Dwarf output, we must assign lexical-blocks id numbers in the order in
@@ -390,26 +401,6 @@ static char *primary_filename;
    assigns numbers to the blocks in the same way.  */
 static unsigned next_block_number = 2;
 
-/* Non-zero if we are performing the file-scope finalization pass and if we
-   should force out Dwarf descriptions of any and all file-scope tagged types
-   which are still incomplete types.  */
-static int finalizing = 0;
-
-/* A pointer to the base of a list of references to DIE's that describe
-   types.  The table is indexed by TYPE_UID() which is a unique number,
-   indentifying each type.  */
-static dw_die_ref *type_die_table;
-
-/* Number of elements currently allocated for type_die_table.  */
-static unsigned type_die_table_allocated;
-
-/* Number of elements in type_die_table currently in use.  */
-static unsigned type_die_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   type_die_table.  */
-#define TYPE_DIE_TABLE_INCREMENT 4096
-
 /* A pointer to the base of a table of references to DIE's that describe
    declarations.  The table is indexed by DECL_UID() which is a unique
    number, indentifying each decl.  */
@@ -458,12 +449,22 @@ static unsigned abbrev_die_table_in_use;
 #define ABBREV_DIE_TABLE_INCREMENT 256
 
 /* A pointer to the base of a table that contains line information
-   for each source code line in the compilation unit.  */
+   for each source code line in .text in the compilation unit.  */
 static dw_line_info_ref line_info_table;
 
 /* Number of elements currently allocated for line_info_table.  */
 static unsigned line_info_table_allocated;
 
+/* Number of elements in separate_line_info_table currently in use.  */
+static unsigned separate_line_info_table_in_use;
+
+/* A pointer to the base of a table that contains line information
+   for each source code line outside of .text in the compilation unit.  */
+static dw_separate_line_info_ref separate_line_info_table;
+
+/* Number of elements currently allocated for separate_line_info_table.  */
+static unsigned separate_line_info_table_allocated;
+
 /* Number of elements in line_info_table currently in use.  */
 static unsigned line_info_table_in_use;
 
@@ -471,11 +472,6 @@ static unsigned line_info_table_in_use;
    line_info_table.  */
 #define LINE_INFO_TABLE_INCREMENT 1024
 
-/* Keep track of the last line_info_table entry number, returned
-   by the prior call to lookup_filename().  This serves as a
-   cache used to speed up file name look ups.  */
-static unsigned prev_file_entry_num = (unsigned) -1;
-
 /* A pointer to the base of a table that contains frame description
    information for each routine.  */
 static dw_fde_ref fde_table;
@@ -490,6 +486,54 @@ static unsigned fde_table_in_use;
    fde_table.  */
 #define FDE_TABLE_INCREMENT 256
 
+/* A list of call frame insns for the CIE.  */
+static dw_cfi_ref cie_cfi_head;
+
+/* A pointer to the base of a table that contains a list of publicly
+   accessible names.  */
+static pubname_ref pubname_table;
+
+/* Number of elements currently allocated for pubname_table.  */
+static unsigned pubname_table_allocated;
+
+/* Number of elements in pubname_table currently in use.  */
+static unsigned pubname_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+   pubname_table.  */
+#define PUBNAME_TABLE_INCREMENT 64
+
+/* A pointer to the base of a table that contains a list of publicly
+   accessible names.  */
+static arange_ref arange_table;
+
+/* Number of elements currently allocated for arange_table.  */
+static unsigned arange_table_allocated;
+
+/* Number of elements in arange_table currently in use.  */
+static unsigned arange_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+   arange_table.  */
+#define ARANGE_TABLE_INCREMENT 64
+
+/* A pointer to the base of a list of pending types which we haven't
+   generated DIEs for yet, but which we will have to come back to
+   later on.  */
+
+static tree *pending_types_list;
+
+/* Number of elements currently allocated for the pending_types_list.  */
+static unsigned pending_types_allocated;
+
+/* Number of elements of pending_types_list currently in use.  */
+static unsigned pending_types;
+
+/* Size (in elements) of increments by which we may expand the pending
+   types list.  Actually, a single hunk of space of this size should
+   be enough for most typical programs.         */
+#define PENDING_TYPES_INCREMENT 64
+
 /* The number of the current function definition for which debugging
    information is being generated.  These numbers range from 1 up to the
    maximum number of function definitions contained within the current
@@ -503,61 +547,9 @@ static unsigned current_funcdef_number = 1;
    associated with the current function (body) definition.  */
 static unsigned current_funcdef_fde;
 
-/* Record the size of the frame, so that the DW_AT_frame_base
-   attribute can be set properly in gen_subprogram_die.  */
-static long int current_funcdef_frame_size = 0;
-
-/* DWARF requires that the compiler's primary datatypes
-   are mapped into a reference to a DIE that defines that
-   primary (base) type.  The base_type_info structure is used
-   to track the correspondence between the name of a
-   base type used by GCC, and its corresponding type
-   characteristics.  Note, that the bt_size field below
-   is the size in bits.  */
-typedef struct base_type_struct *base_type_ref;
-typedef struct base_type_struct
-  {
-    char *bt_name;
-    enum dwarf_type bt_type;
-    int bt_is_signed;
-    int bt_size;
-  }
-base_type_info;
-
-/* Characteristics of base types used by the compiler.  */
-static base_type_info base_type_table[] =
-{
-  {"void", DW_ATE_unsigned, 0, 0},
-  /* TODO: on some architectures, "char" may be signed. */
-  {"char", DW_ATE_unsigned_char, 0, CHAR_TYPE_SIZE},
-  {"unsigned char", DW_ATE_unsigned_char, 0, CHAR_TYPE_SIZE},
-  {"signed char", DW_ATE_signed_char, 1, CHAR_TYPE_SIZE},
-  {"int", DW_ATE_signed, 1, /* INT_TYPE_SIZE */ 4*8},
-  {"unsigned int", DW_ATE_unsigned, 0, /* INT_TYPE_SIZE */ 4*8},
-  {"short", DW_ATE_signed, 1, SHORT_TYPE_SIZE},
-  {"short int", DW_ATE_signed, 1, SHORT_TYPE_SIZE},
-  {"short unsigned int", DW_ATE_unsigned, 0, SHORT_TYPE_SIZE},
-  {"long", DW_ATE_signed, 1, /* LONG_TYPE_SIZE */ 4*8},
-  {"long int", DW_ATE_signed, 1, /* LONG_TYPE_SIZE */ 4*8},
-  {"long unsigned int", DW_ATE_unsigned, 0, /* LONG_TYPE_SIZE */ 4*8},
-  {"long long int", DW_ATE_signed, 1, LONG_LONG_TYPE_SIZE},
-  {"long long unsigned int", DW_ATE_unsigned, 0, LONG_LONG_TYPE_SIZE},
-  {"float", DW_ATE_float, 1, /* FLOAT_TYPE_SIZE */ 4*8},
-  {"double", DW_ATE_float, 1, DOUBLE_TYPE_SIZE},
-  {"long double", DW_ATE_float, 1, LONG_DOUBLE_TYPE_SIZE},
-  {"complex", DW_ATE_complex_float, 1, 2 * /* FLOAT_TYPE_SIZE */ 4*8},
-  {"double complex", DW_ATE_complex_float, 1, 2 * DOUBLE_TYPE_SIZE},
-  {"long double complex", DW_ATE_complex_float, 1, 2 * LONG_DOUBLE_TYPE_SIZE}
-};
-#define NUM_BASE_TYPES (sizeof(base_type_table)/sizeof(base_type_info))
-
-/* Record the DIE associated with a given base type  This table is
-   parallel to the base_type_table, and records the DIE genereated
-   to describe base type that has been previously referenced.  */
-static dw_die_ref base_type_die_table[NUM_BASE_TYPES];
-
-/* This predefined base type is used to create certain anonymous types */
-static dw_die_ref int_base_type_die;
+/* Record whether the function being analyzed contains inlined functions.  */
+static int current_function_has_inlines;
+static int comp_unit_has_inlines;
 
 /* A pointer to the ..._DECL node which we have most recently been working
    on.  We keep this around just in case something about it looks screwy and
@@ -565,32 +557,235 @@ static dw_die_ref int_base_type_die;
    declaration are.  */
 static tree dwarf_last_decl;
 
-/* A list of DIE reference attributes values that need backchaining
-   support.  */
-static backchain_ref backchain;
-
 /* Forward declarations for functions defined in this file.  */
-static void gen_type_die ();
-static void add_type_attribute ();
-static void decls_for_scope ();
-static void gen_decl_die ();
-static unsigned lookup_filename ();
 
+static char *stripattributes           PROTO((char *));
+static void addr_const_to_string       PROTO((char *, rtx));
+static char *addr_to_string            PROTO((rtx));
+static int is_pseudo_reg               PROTO((rtx));
+static tree type_main_variant          PROTO((tree));
+static int is_tagged_type              PROTO((tree));
+static char *dwarf_tag_name            PROTO((unsigned));
+static char *dwarf_attr_name           PROTO((unsigned));
+static char *dwarf_form_name           PROTO((unsigned));
+static char *dwarf_stack_op_name       PROTO((unsigned));
+static char *dwarf_type_encoding_name  PROTO((unsigned));
+static char *dward_cfi_name            PROTO((unsigned));
+static tree decl_ultimate_origin       PROTO((tree));
+static tree block_ultimate_origin      PROTO((tree));
+static tree decl_class_context         PROTO((tree));
+static void add_dwarf_attr             PROTO((dw_die_ref, dw_attr_ref));
+static void add_AT_flag                        PROTO((dw_die_ref,
+                                              enum dwarf_attribute,
+                                              unsigned));
+static void add_AT_int                 PROTO((dw_die_ref,
+                                              enum dwarf_attribute, long));
+static void add_AT_unsigned            PROTO((dw_die_ref,
+                                              enum dwarf_attribute,
+                                              unsigned long));
+static void add_AT_long_long           PROTO((dw_die_ref,
+                                              enum dwarf_attribute,
+                                              unsigned long, unsigned long));
+static void add_AT_float               PROTO((dw_die_ref,
+                                              enum dwarf_attribute,
+                                              unsigned, long *));
+static void add_AT_string              PROTO((dw_die_ref,
+                                              enum dwarf_attribute, char *));
+static void add_AT_die_ref             PROTO((dw_die_ref,
+                                              enum dwarf_attribute,
+                                              dw_die_ref));
+static void add_AT_fde_ref             PROTO((dw_die_ref,
+                                              enum dwarf_attribute,
+                                              unsigned));
+static void add_AT_loc                 PROTO((dw_die_ref,
+                                              enum dwarf_attribute,
+                                              dw_loc_descr_ref));
+static void add_AT_addr                        PROTO((dw_die_ref,
+                                              enum dwarf_attribute, char *));
+static void add_AT_lbl_id              PROTO((dw_die_ref,
+                                              enum dwarf_attribute, char *));
+static void add_AT_setion_offset       PROTO((dw_die_ref,
+                                              enum dwarf_attribute, char *));
+static int is_extern_subr_die          PROTO((dw_die_ref));
+static dw_attr_ref get_AT              PROTO((dw_die_ref,
+                                              enum dwarf_attribute));
+static char *get_AT_low_pc             PROTO((dw_die_ref));
+static char *get_AT_hi_pc              PROTO((dw_die_ref));
+static char *get_AT_string             PROTO((dw_die_ref,
+                                              enum dwarf_attribute));
+static int get_AT_flag                 PROTO((dw_die_ref,
+                                              enum dwarf_attribute));
+static unsigned get_AT_unsigned                PROTO((dw_die_ref,
+                                              enum dwarf_attribute));
+static int is_c_family                 PROTO((void));
+static int is_fortran                  PROTO((void));
+static void remove_AT                  PROTO((dw_die_ref,
+                                              enum dwarf_attribute));
+static void remove_children            PROTO((dw_die_ref));
+static void add_child_die              PROTO((dw_die_ref, dw_die_ref));
+static dw_die_ref new_die              PROTO((enum dwarf_tag, dw_die_ref));
+static dw_die_ref lookup_type_die      PROTO((tree));
+static void equate_type_number_to_die  PROTO((tree, dw_die_ref));
+static dw_die_ref lookup_decl_die      PROTO((tree));
+static void equate_decl_number_to_die  PROTO((tree, dw_die_ref));
+static dw_loc_descr_ref new_loc_descr  PROTO((enum dwarf_location_atom,
+                                              unsigned long, unsigned long));
+static void add_loc_descr              PROTO((dw_loc_descr_ref *,
+                                              dw_loc_descr_ref));
+static dw_cfi_ref new_cfe              PROTO((void));
+static void add_cfe                    PROTO((dw_cfi_ref *, dw_cfi_ref));
+static void print_spaces               PROTO((FILE *));
+static void print_die                  PROTO((dw_die_ref, FILE *));
+static void print_dwarf_line_table     PROTO((FILE *));
+static void add_sibling_atttributes    PROTO((dw_die_ref));
+static void build_abbrev_table         PROTO((dw_die_ref));
+static unsigned long size_of_uleb128   PROTO((unsigned long));
+static unsigned long size_of_sleb128   PROTO((long));
+static unsigned long size_of_string    PROTO((char *));
+static unsigned long size_of_loc_descr PROTO((dw_loc_descr_ref));
+static unsigned long size_of_locs      PROTO((dw_loc_descr_ref));
+static int constant_size               PROTO((long unsigned));
+static unsigned long size_of_die       PROTO((dw_die_ref));
+static void calc_die_sizes             PROTO((dw_die_ref));
+static unsigned long size_of_prolog    PROTO((void));
+static unsigned long size_of_line_info PROTO((void));
+static unsigned long size_of_pubnames  PROTO((void));
+static unsigned long size_of_aranges   PROTO((void));
+static void output_uleb128             PROTO((unsigned long));
+static void output_sleb128             PROTO((long));
+static enum dwarf_form value_format    PROTO((dw_val_ref));
+static void output_value_format                PROTO((dw_val_ref));
+static void output_abbrev_section      PROTO((void));
+static void output_loc_operands                PROTO((dw_loc_descr_ref));
+static unsigned long sibling_offset    PROTO((dw_die_ref));
+static void output_die                 PROTO((dw_die_ref));
+static void output_compilation_unit_header PROTO((void));
+static char *dwarf2out_cfi_label       PROTO((void));
+static void add_fde_cfi                        PROTO((char *, dw_cfi_ref));
+static void lookup_cfa_1               PROTO((dw_cfi_ref, unsigned long *,
+                                              long *));
+static void lookup_cfa                 PROTO((unsigned long *, long *));
+static void reg_save                   PROTO((char *, unsigned, unsigned,
+                                              long));
+static void initial_return_save                PROTO((rtx));
+static unsigned long size_of_cfi       PROTO((dw_cfi_ref));
+static unsigned long size_of_fde       PROTO((dw_fde_ref, unsigned long *));
+static void calc_fde_sizes             PROTO((void));
+static void output_cfi                 PROTO((dw_cfi_ref, dw_fde_ref));
+static void output_call_frame_info     PROTO((void));
+static char *dwarf2_name               PROTO((tree, int));
+static void add_pubname                        PROTO((tree, dw_die_ref));
+static void output_pubnames            PROTO((void));
+static void add_arrange                        PROTO((tree, dw_die_ref));
+static void output_arranges            PROTO((void));
+static void output_line_info           PROTO((void));
+static int is_body_block               PROTO((tree));
+static dw_die_ref base_type_die                PROTO((tree));
+static tree root_type                  PROTO((tree));
+static int is_base_type                        PROTO((tree));
+static dw_die_ref modified_type_die    PROTO((tree, int, int, dw_die_ref));
+static int type_is_enum                        PROTO((tree));
+static unsigned reg_number             PROTO((rtx));
+static dw_loc_descr_ref reg_loc_descr_ref PROTO((rtx));
+static dw_loc_descr_ref based_loc_descr        PROTO((unsigned, long));
+static int is_based_loc                        PROTO((rtx));
+static dw_loc_descr_ref mem_loc_descriptor PROTO((rtx));
+static dw_loc_descr_ref loc_descriptor PROTO((rtx));
+static unsigned ceiling                        PROTO((unsigned, unsigned));
+static tree field_type                 PROTO((tree));
+static unsigned simple_type_align_in_bits PROTO((tree));
+static unsigned simple_type_size_in_bits PROTO((tree));
+static unsigned field_byte_offset              PROTO((tree));
+static void add_location_attribute     PROTO((dw_die_ref, rtx));
+static void add_data_member_location_attribute PROTO((dw_die_ref, tree));
+static void add_const_value_attribute  PROTO((dw_die_ref, rtx));
+static void add_location_or_const_value_attribute PROTO((dw_die_ref, tree));
+static void add_name_attribute         PROTO((dw_die_ref, char *));
+static void add_bound_info             PROTO((dw_die_ref,
+                                              enum dwarf_attribute, tree));
+static void add_subscript_info         PROTO((dw_die_ref, tree));
+static void add_byte_size_attribute    PROTO((dw_die_ref, tree));
+static void add_bit_offset_attribute   PROTO((dw_die_ref, tree));
+static void add_bit_size_attribute     PROTO((dw_die_ref, tree));
+static void add_prototyped_attribute   PROTO((dw_die_ref, tree));
+static void add_abstract_origin_attribute PROTO((dw_die_ref, tree));
+static void add_pure_or_virtual_attribute PROTO((dw_die_ref, tree));
+static void add_src_coords_attributes  PROTO((dw_die_ref, tree));
+static void ad_name_and_src_coords_attributes PROTO((dw_die_ref, tree));
+static void push_decl_scope            PROTO((tree));
+static dw_die_ref scope_die_for                PROTO((tree, dw_die_ref));
+static void pop_decl_scope             PROTO((void));
+static void add_type_attribute         PROTO((dw_die_ref, tree, int, int,
+                                              dw_die_ref));
+static char *type_tag                  PROTO((tree));
+static tree member_declared_type       PROTO((tree));
+static char *decl_start_label          PROTO((tree));
+static void gen_arrqay_type_die                PROTO((tree, dw_die_ref));
+static void gen_set_type_die           PROTO((tree, dw_die_ref));
+static void gen_entry_point_die                PROTO((tree, dw_die_ref));
+static void pend_type                  PROTO((tree));
+static void output_pending_types_for_scope PROTO((dw_die_ref));
+static void gen_inlined_enumeration_type_die PROTO((tree, dw_die_ref));
+static void gen_inlined_structure_type_die PROTO((tree, dw_die_ref));
+static void gen_inlined_union_type_die PROTO((tree, dw_die_ref));
+static void gen_enumeration_type_die   PROTO((tree, dw_die_ref));
+static dw_die_ref gen_formal_parameter_die PROTO((tree, dw_die_ref));
+static void gen_unspecified_parameters_die PROTO((tree, dw_die_ref));
+static void gen_formal_types_die       PROTO((tree, dw_die_ref));
+static void gen_subprogram_die         PROTO((tree, dw_die_ref));
+static void gen_variable_die           PROTO((tree, dw_die_ref));
+static void gen_labeld_die             PROTO((tree, dw_die_ref));
+static void gen_lexical_block_die      PROTO((tree, dw_die_ref, int));
+static void gen_inlined_subprogram_die PROTO((tree, dw_die_ref, int));
+static void gen_field_die              PROTO((tree, dw_die_ref));
+static void gen_ptr_to_mbr_type_die    PROTO((tree, dw_die_ref));
+static void gen_compile_unit_die       PROTO((char *));
+static void gen_string_type_die                PROTO((tree, dw_die_ref));
+static void gen_inheritance_die                PROTO((tree, dw_die_ref));
+static void gen_member_die             PROTO((tree, dw_die_ref));
+static void gen_struct_or_union_type_die PROTO((tree, dw_die_ref));
+static void gen_subroutine_type_die    PROTO((tree, dw_die_ref));
+static void gen_typedef_die            PROTO((tree, dw_die_ref));
+static void gen_type_die               PROTO((tree, dw_die_ref));
+static void gen_tagged_type_instantiation_die PROTO((tree, dw_die_ref));
+static void gen_block_die              PROTO((tree, dw_die_ref, int));
+static void decls_for_scope            PROTO((tree, dw_die_ref, int));
+static int is_redundant_typedef                PROTO((tree));
+static void gen_decl_die               PROTO((tree, dw_die_ref));
+static unsigned lookup_filename                PROTO((char *));
 
 /* Definitions of defaults for assembler-dependent names of various
    pseudo-ops and section names.
    Theses may be overridden in the tm.h file (if necessary) for a particular
    assembler.  */
+
 #ifndef UNALIGNED_SHORT_ASM_OP
 #define UNALIGNED_SHORT_ASM_OP ".2byte"
 #endif
 #ifndef UNALIGNED_INT_ASM_OP
 #define UNALIGNED_INT_ASM_OP   ".4byte"
 #endif
+#ifndef UNALIGNED_DOUBLE_INT_ASM_OP
+#define UNALIGNED_DOUBLE_INT_ASM_OP    ".8byte"
+#endif
 #ifndef ASM_BYTE_OP
 #define ASM_BYTE_OP            ".byte"
 #endif
 
+#ifndef UNALIGNED_OFFSET_ASM_OP
+#define UNALIGNED_OFFSET_ASM_OP \
+  (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
+#endif
+
+#ifndef UNALIGNED_WORD_ASM_OP
+#define UNALIGNED_WORD_ASM_OP \
+  (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
+#endif
+
+/* Data and reference forms for relocatable data.  */
+#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
+#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
+
 /* Pseudo-op for defining a new section.  */
 #ifndef SECTION_ASM_OP
 #define SECTION_ASM_OP ".section"
@@ -640,15 +835,6 @@ static unsigned lookup_filename ();
 #ifndef DATA_SECTION
 #define DATA_SECTION           ".data"
 #endif
-#ifndef DATA1_SECTION
-#define DATA1_SECTION          ".data1"
-#endif
-#ifndef RODATA_SECTION
-#define RODATA_SECTION         ".rodata"
-#endif
-#ifndef RODATA1_SECTION
-#define RODATA1_SECTION                ".rodata1"
-#endif
 #ifndef BSS_SECTION
 #define BSS_SECTION            ".bss"
 #endif
@@ -658,73 +844,51 @@ static unsigned lookup_filename ();
    (artificial) labels which may be generated within this file (when the -g
    options is used and DWARF_DEBUGGING_INFO is in effect.
    If necessary, these may be overridden from within the tm.h file, but
-   typically, overriding these defaults is unnecessary.
-   These labels have been hacked so that they all begin with a
-   `.L' sequence to appease the stock sparc/svr4 assembler and the
-   stock m88k/svr4 assembler, both of which need to see .L at the start of a
-   label in order to prevent that label from going into the linker symbol
-   table).  Eventually, the ASM_GENERATE_INTERNAL_LABEL and 
-   ASM_OUTPUT_INTERNAL_LABEL should be used, but that will require
-   a major rework.  */
-#ifndef TEXT_BEGIN_LABEL
-#define TEXT_BEGIN_LABEL       ".L_text_b"
-#endif
+   typically, overriding these defaults is unnecessary.  */
+
+char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+
 #ifndef TEXT_END_LABEL
-#define TEXT_END_LABEL         ".L_text_e"
-#endif
-#ifndef DATA_BEGIN_LABEL
-#define DATA_BEGIN_LABEL       ".L_data_b"
+#define TEXT_END_LABEL         "Letext"
 #endif
 #ifndef DATA_END_LABEL
-#define DATA_END_LABEL         ".L_data_e"
-#endif
-#ifndef RODATA_BEGIN_LABEL
-#define RODATA_BEGIN_LABEL     ".L_rodata_b"
-#endif
-#ifndef RODATA_END_LABEL
-#define RODATA_END_LABEL       ".L_rodata_e"
-#endif
-#ifndef BSS_BEGIN_LABEL
-#define BSS_BEGIN_LABEL                ".L_bss_b"
+#define DATA_END_LABEL         "Ledata"
 #endif
 #ifndef BSS_END_LABEL
-#define BSS_END_LABEL          ".L_bss_e"
-#endif
-#ifndef LINE_BEGIN_LABEL
-#define LINE_BEGIN_LABEL       ".L_line_b"
-#endif
-#ifndef LINE_END_LABEL
-#define LINE_END_LABEL         ".L_line_e"
+#define BSS_END_LABEL           "Lebss"
 #endif
 #ifndef INSN_LABEL_FMT
-#define INSN_LABEL_FMT         ".L_I%u_%u"
+#define INSN_LABEL_FMT         "LI%u_"
 #endif
-#ifndef BLOCK_BEGIN_LABEL_FMT
-#define BLOCK_BEGIN_LABEL_FMT  ".L_B%u"
+#ifndef BLOCK_BEGIN_LABEL
+#define BLOCK_BEGIN_LABEL      "LBB"
 #endif
-#ifndef BLOCK_END_LABEL_FMT
-#define BLOCK_END_LABEL_FMT    ".L_B%u_e"
+#ifndef BLOCK_END_LABEL
+#define BLOCK_END_LABEL                "LBE"
 #endif
-#ifndef BODY_BEGIN_LABEL_FMT
-#define BODY_BEGIN_LABEL_FMT   ".L_b%u"
+#ifndef BODY_BEGIN_LABEL
+#define BODY_BEGIN_LABEL       "Lbb"
 #endif
-#ifndef BODY_END_LABEL_FMT
-#define BODY_END_LABEL_FMT     ".L_b%u_e"
+#ifndef BODY_END_LABEL
+#define BODY_END_LABEL         "Lbe"
 #endif
-#ifndef FUNC_END_LABEL_FMT
-#define FUNC_END_LABEL_FMT     ".L_f%u_e"
+#ifndef FUNC_BEGIN_LABEL
+#define FUNC_BEGIN_LABEL       "LFB"
 #endif
-#ifndef LINE_CODE_LABEL_FMT
-#define LINE_CODE_LABEL_FMT    ".L_LC%u"
+#ifndef FUNC_END_LABEL
+#define FUNC_END_LABEL         "LFE"
 #endif
-#ifndef SFNAMES_ENTRY_LABEL_FMT
-#define SFNAMES_ENTRY_LABEL_FMT        ".L_F%u"
+#ifndef LINE_CODE_LABEL
+#define LINE_CODE_LABEL                "LM"
+#endif
+#ifndef SEPARATE_LINE_CODE_LABEL
+#define SEPARATE_LINE_CODE_LABEL       "LSM"
 #endif
-
 
 /* Definitions of defaults for various types of primitive assembly language
    output operations.  These may be overridden from within the tm.h file,
    but typically, that is unecessary.  */
+
 #ifndef ASM_OUTPUT_SECTION
 #define ASM_OUTPUT_SECTION(FILE, SECTION) \
   fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION)
@@ -748,16 +912,41 @@ static unsigned lookup_filename ();
   } while (0)
 #endif
 
+#ifndef ASM_OUTPUT_DWARF_DELTA
+#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2)                     \
+ do {  fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP);            \
+       assemble_name (FILE, LABEL1);                                   \
+       fprintf (FILE, "-");                                            \
+       assemble_name (FILE, LABEL2);                                   \
+  } while (0)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA
+#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2)                        \
+ do {  fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP);              \
+       assemble_name (FILE, LABEL1);                                   \
+       fprintf (FILE, "-");                                            \
+       assemble_name (FILE, LABEL2);                                   \
+  } while (0)
+#endif
+
 #ifndef ASM_OUTPUT_DWARF_ADDR
 #define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL)                              \
- do {  fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP);               \
+ do {  fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP);              \
        assemble_name (FILE, LABEL);                                    \
   } while (0)
 #endif
 
 #ifndef ASM_OUTPUT_DWARF_ADDR_CONST
 #define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR)                         \
-    fprintf ((FILE), "\t%s\t%s", UNALIGNED_INT_ASM_OP, (ADDR))
+  fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR))
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_OFFSET
+#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL)                            \
+ do {  fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP);            \
+       assemble_name (FILE, LABEL);                                    \
+  } while (0)
 #endif
 
 #ifndef ASM_OUTPUT_DWARF_DATA1
@@ -775,6 +964,18 @@ static unsigned lookup_filename ();
   fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) VALUE)
 #endif
 
+#ifndef ASM_OUTPUT_DWARF_DATA
+#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \
+  fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \
+          (unsigned long) VALUE)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_ADDR_DATA
+#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \
+  fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \
+          (unsigned long) VALUE)
+#endif
+
 #ifndef ASM_OUTPUT_DWARF_DATA8
 #define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE)              \
   do {                                                                 \
@@ -832,30 +1033,46 @@ static unsigned lookup_filename ();
   while (0)
 #endif
 
-\f
-/************************ general utility functions **************************/
+/* The DWARF 2 CFA column which tracks the return address.  Normally this
+   is the column for PC, or the first column after all of the hard
+   registers.  */
+#ifndef DWARF_FRAME_RETURN_COLUMN
+#ifdef PC_REGNUM
+#define DWARF_FRAME_RETURN_COLUMN      DWARF_FRAME_REGNUM (PC_REGNUM)
+#else
+#define DWARF_FRAME_RETURN_COLUMN      FIRST_PSEUDO_REGISTER
+#endif
+#endif
 
-/* Return a pointer to a copy of the section string name 's' with all
+/* The mapping from gcc register number to DWARF 2 CFA column number.  By
+   default, we just provide columns for all registers.  */
+#ifndef DWARF_FRAME_REGNUM
+#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
+#endif
+\f
+/* Return a pointer to a copy of the section string name S with all
    attributes stripped off.  */
-inline char *
+
+static inline char *
 stripattributes (s)
-     register char *s;
+     char *s;
 {
-  register char *stripped, *p;
-  stripped = xstrdup (s);
-  p = stripped;
+  char *stripped = xstrdup (s);
+  char *p = stripped;
+
   while (*p && *p != ',')
     p++;
+
   *p = '\0';
   return stripped;
 }
 
-/* Convert an integer constant expression into assembler syntax.
-   Addition and subtraction are the only arithmetic
-   that may appear in these expressions.   This is an adaptation
-   of output_addr_const() in final.c.   Here, the target of the
-   conversion is a string buffer.  We can't use output_addr_const
-   directly, because it writes to a file.  */
+/* Convert an integer constant expression into assembler syntax.  Addition
+   and subtraction are the only arithmetic that may appear in these
+   expressions.   This is an adaptation of output_addr_const in final.c.
+   Here, the target of the conversion is a string buffer.  We can't use
+   output_addr_const directly, because it writes to a file.  */
+
 static void
 addr_const_to_string (str, x)
      char *str;
@@ -893,13 +1110,7 @@ restart:
       break;
 
     case CONST_INT:
-      sprintf (buf1,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-              "%d",
-#else
-              "%ld",
-#endif
-              INTVAL (x));
+      sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
       strcat (str, buf1);
       break;
 
@@ -915,36 +1126,12 @@ restart:
        {
          /* We can use %d if the number is one word and positive.  */
          if (CONST_DOUBLE_HIGH (x))
-           sprintf (buf1,
-#if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
-                    "0x%lx%016lx",
-#else
-                    "0x%x%016x",
-#endif
-#else
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
-                    "0x%lx%08lx",
-#else
-                    "0x%x%08x",
-#endif
-#endif
+           sprintf (buf1, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
                     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
          else if (CONST_DOUBLE_LOW (x) < 0)
-           sprintf (buf1,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-                    "0x%x",
-#else
-                    "0x%lx",
-#endif
-                    CONST_DOUBLE_LOW (x));
+           sprintf (buf1, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
          else
-           sprintf (buf1,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-                    "%d",
-#else
-                    "%ld",
-#endif
+           sprintf (buf1, HOST_WIDE_INT_PRINT_DEC,
                     CONST_DOUBLE_LOW (x));
          strcat (str, buf1);
        }
@@ -962,6 +1149,7 @@ restart:
          strcat (str, buf1);
          if (INTVAL (XEXP (x, 0)) >= 0)
            strcat (str, "+");
+
          addr_const_to_string (buf1, XEXP (x, 0));
          strcat (str, buf1);
        }
@@ -969,10 +1157,11 @@ restart:
        {
          addr_const_to_string (buf1, XEXP (x, 0));
          strcat (str, buf1);
-         if (INTVAL (XEXP (x, 0)) >= 0)
+         if (INTVAL (XEXP (x, 1)) >= 0)
            strcat (str, "+");
+
          addr_const_to_string (buf1, XEXP (x, 1));
-         strcat (str, buf2);
+         strcat (str, buf1);
        }
       break;
 
@@ -1014,6 +1203,7 @@ restart:
 
 /* Convert an address constant to a string, and return a pointer to
    a copy of the result, located on the heap.  */
+
 static char *
 addr_to_string (x)
      rtx x;
@@ -1024,7 +1214,8 @@ addr_to_string (x)
 }
 
 /* Test if rtl node points to a psuedo register.  */
-inline int
+
+static inline int
 is_pseudo_reg (rtl)
      register rtx rtl;
 {
@@ -1033,10 +1224,10 @@ is_pseudo_reg (rtl)
              && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
 }
 
-
 /* Return a reference to a type, with its const and volatile qualifiers
    removed.  */
-inline tree
+
+static inline tree
 type_main_variant (type)
      register tree type;
 {
@@ -1046,16 +1237,17 @@ type_main_variant (type)
      of a given type (and all of the MAIN_VARIANT values for all members of
      the group should point to that one type) but sometimes the C front-end
      messes this up for array types, so we work around that bug here.  */
+
   if (TREE_CODE (type) == ARRAY_TYPE)
-    {
-      while (type != TYPE_MAIN_VARIANT (type))
-       type = TYPE_MAIN_VARIANT (type);
-    }
+    while (type != TYPE_MAIN_VARIANT (type))
+      type = TYPE_MAIN_VARIANT (type);
+
   return type;
 }
 
 /* Return non-zero if the given type node represents a tagged type.  */
-inline int
+
+static inline int
 is_tagged_type (type)
      register tree type;
 {
@@ -1066,6 +1258,7 @@ is_tagged_type (type)
 }
 
 /* Convert a DIE tag into its string name.  */
+
 static char *
 dwarf_tag_name (tag)
      register unsigned tag;
@@ -1182,6 +1375,7 @@ dwarf_tag_name (tag)
 }
 
 /* Convert a DWARF attribute code into its string name.  */
+
 static char *
 dwarf_attr_name (attr)
      register unsigned attr;
@@ -1313,7 +1507,6 @@ dwarf_attr_name (attr)
     case DW_AT_vtable_elem_location:
       return "DW_AT_vtable_elem_location";
 
-#ifdef MIPS_DEBUGGING_INFO
     case DW_AT_MIPS_fde:
       return "DW_AT_MIPS_fde";
     case DW_AT_MIPS_loop_begin:
@@ -1328,7 +1521,14 @@ dwarf_attr_name (attr)
       return "DW_AT_MIPS_software_pipeline_depth";
     case DW_AT_MIPS_linkage_name:
       return "DW_AT_MIPS_linkage_name";
-#endif
+    case DW_AT_MIPS_stride:
+      return "DW_AT_MIPS_stride";
+    case DW_AT_MIPS_abstract_name:
+      return "DW_AT_MIPS_abstract_name";
+    case DW_AT_MIPS_clone_origin:
+      return "DW_AT_MIPS_clone_origin";
+    case DW_AT_MIPS_has_inlines:
+      return "DW_AT_MIPS_has_inlines";
 
     case DW_AT_sf_names:
       return "DW_AT_sf_names";
@@ -1348,6 +1548,7 @@ dwarf_attr_name (attr)
 }
 
 /* Convert a DWARF value form code into its string name.  */
+
 static char *
 dwarf_form_name (form)
      register unsigned form;
@@ -1402,6 +1603,7 @@ dwarf_form_name (form)
 }
 
 /* Convert a DWARF stack opcode into its string name.  */
+
 static char *
 dwarf_stack_op_name (op)
      register unsigned op;
@@ -1704,6 +1906,7 @@ dwarf_stack_op_name (op)
 }
 
 /* Convert a DWARF type code into its string name.  */
+
 static char *
 dwarf_type_encoding_name (enc)
      register unsigned enc;
@@ -1732,6 +1935,7 @@ dwarf_type_encoding_name (enc)
 }
 
 /* Convert a DWARF call frame info. operation to its string name */
+
 static char *
 dwarf_cfi_name (cfi_opc)
      register unsigned cfi_opc;
@@ -1787,14 +1991,15 @@ dwarf_cfi_name (cfi_opc)
    function, so we have to trace all of the way back through the origin chain
    to find out what sort of node actually served as the original seed for the
    given block.  */
+
 static tree
 decl_ultimate_origin (decl)
      register tree decl;
 {
   register tree immediate_origin = DECL_ABSTRACT_ORIGIN (decl);
 
-  if (immediate_origin == NULL)
-    return NULL;
+  if (immediate_origin == NULL_TREE)
+    return NULL_TREE;
   else
     {
       register tree ret_val;
@@ -1806,6 +2011,7 @@ decl_ultimate_origin (decl)
          lookahead = DECL_ABSTRACT_ORIGIN (ret_val);
        }
       while (lookahead != NULL && lookahead != ret_val);
+
       return ret_val;
     }
 }
@@ -1815,14 +2021,15 @@ decl_ultimate_origin (decl)
    function, so we have to trace all of the way back through the origin chain
    to find out what sort of node actually served as the original seed for the
    given block.  */
+
 static tree
 block_ultimate_origin (block)
      register tree block;
 {
   register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
 
-  if (immediate_origin == NULL)
-    return NULL;
+  if (immediate_origin == NULL_TREE)
+    return NULL_TREE;
   else
     {
       register tree ret_val;
@@ -1836,14 +2043,36 @@ block_ultimate_origin (block)
            : NULL;
        }
       while (lookahead != NULL && lookahead != ret_val);
+
       return ret_val;
     }
 }
-\f
-/**************** DIE internal representation constturction *******************/
 
+/* Get the class to which DECL belongs, if any.  In g++, the DECL_CONTEXT
+   of a virtual function may refer to a base class, so we check the 'this'
+   parameter.  */
+
+static tree
+decl_class_context (decl)
+     tree decl;
+{
+  tree context = NULL_TREE;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
+    context = DECL_CONTEXT (decl);
+  else
+    context = TYPE_MAIN_VARIANT
+      (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
+
+  if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't')
+    context = NULL_TREE;
+
+  return context;
+}
+\f
 /* Add an attribute/value pair to a DIE */
-inline void
+
+static inline void
 add_dwarf_attr (die, attr)
      register dw_die_ref die;
      register dw_attr_ref attr;
@@ -1864,232 +2093,224 @@ add_dwarf_attr (die, attr)
 }
 
 /* Add a flag value attribute to a DIE.  */
-inline void
+
+static inline void
 add_AT_flag (die, attr_kind, flag)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register unsigned flag;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_flag;
-      attr->dw_attr_val.v.val_flag = flag;
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_flag;
+  attr->dw_attr_val.v.val_flag = flag;
+  add_dwarf_attr (die, attr);
 }
 
 /* Add a signed integer attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_int (die, attr_kind, int_val)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register long int int_val;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_const;
-      attr->dw_attr_val.v.val_int = int_val;
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_const;
+  attr->dw_attr_val.v.val_int = int_val;
+  add_dwarf_attr (die, attr);
 }
 
 /* Add an unsigned integer attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_unsigned (die, attr_kind, unsigned_val)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register unsigned long unsigned_val;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_unsigned_const;
-      attr->dw_attr_val.v.val_unsigned = unsigned_val;
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_unsigned_const;
+  attr->dw_attr_val.v.val_unsigned = unsigned_val;
+  add_dwarf_attr (die, attr);
 }
 
 /* Add an unsigned double integer attribute value to a DIE.  */
-inline void
-add_AT_double (die, attr_kind, val_hi, val_low)
+
+static inline void
+add_AT_long_long (die, attr_kind, val_hi, val_low)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register unsigned long val_hi;
      register unsigned long val_low;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_double_const;
-      attr->dw_attr_val.v.val_dbl_const.dw_dbl_hi = val_hi;
-      attr->dw_attr_val.v.val_dbl_const.dw_dbl_low = val_low;
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_long_long;
+  attr->dw_attr_val.v.val_long_long.hi = val_hi;
+  attr->dw_attr_val.v.val_long_long.low = val_low;
+  add_dwarf_attr (die, attr);
+}
+
+/* Add a floating point attribute value to a DIE and return it.  */
+
+static inline void
+add_AT_float (die, attr_kind, length, array)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
+     register unsigned length;
+     register long *array;
+{
+  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_float;
+  attr->dw_attr_val.v.val_float.length = length;
+  attr->dw_attr_val.v.val_float.array = array;
+  add_dwarf_attr (die, attr);
 }
 
 /* Add a string attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_string (die, attr_kind, str)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register char *str;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_str;
-      attr->dw_attr_val.v.val_str = xstrdup (str);
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_str;
+  attr->dw_attr_val.v.val_str = xstrdup (str);
+  add_dwarf_attr (die, attr);
 }
 
 /* Add a DIE reference attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_die_ref (die, attr_kind, targ_die)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register dw_die_ref targ_die;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_die_ref;
-      attr->dw_attr_val.v.val_die_ref = targ_die;
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_die_ref;
+  attr->dw_attr_val.v.val_die_ref = targ_die;
+  add_dwarf_attr (die, attr);
 }
 
 /* Add an FDE reference attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_fde_ref (die, attr_kind, targ_fde)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register unsigned targ_fde;
 {
-  register dw_attr_ref attr;
+  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
 
-  attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_fde_ref;
-      attr->dw_attr_val.v.val_fde_index = targ_fde;
-      add_dwarf_attr (die, attr);
-    }
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_fde_ref;
+  attr->dw_attr_val.v.val_fde_index = targ_fde;
+  add_dwarf_attr (die, attr);
 }
 
 /* Add a location description attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_loc (die, attr_kind, loc)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register dw_loc_descr_ref loc;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_loc;
-      attr->dw_attr_val.v.val_loc = loc;
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_loc;
+  attr->dw_attr_val.v.val_loc = loc;
+  add_dwarf_attr (die, attr);
 }
 
 /* Add an address constant attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_addr (die, attr_kind, addr)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      char *addr;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_addr;
-      attr->dw_attr_val.v.val_addr = addr;
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_addr;
+  attr->dw_attr_val.v.val_addr = addr;
+  add_dwarf_attr (die, attr);
 }
 
 /* Add a label identifier attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_lbl_id (die, attr_kind, lbl_id)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register char *lbl_id;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_lbl_id;
-      attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
-      add_dwarf_attr (die, attr);
-    }
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_lbl_id;
+  attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
+  add_dwarf_attr (die, attr);
 }
 
 /* Add a section offset attribute value to a DIE.  */
-inline void
+
+static inline void
 add_AT_section_offset (die, attr_kind, section)
      register dw_die_ref die;
      register enum dwarf_attribute attr_kind;
      register char *section;
 {
   register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-  if (attr != NULL)
-    {
-      attr->dw_attr_next = NULL;
-      attr->dw_attr = attr_kind;
-      attr->dw_attr_val.val_class = dw_val_class_section_offset;
-      attr->dw_attr_val.v.val_section = section;
-      add_dwarf_attr (die, attr);
-    }
-}
-
-/* Save a DIE reference attribute value to a DIE for later backchaining.  */
-inline void
-backchain_AT_die_ref (type, placeholder)
-     register tree type;
-     register dw_die_ref placeholder;
-{
-  register backchain_ref back = (backchain_ref) xmalloc (sizeof (backchain_t));
-  if (back != NULL)
-    {
-      back->type = type;
-      back->placeholder = placeholder;
 
-      back->next = backchain;
-      backchain = back;
-    }
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_section_offset;
+  attr->dw_attr_val.v.val_section = section;
+  add_dwarf_attr (die, attr);
+  
 }
 
 /* Test if die refers to an external subroutine.  */
-inline int
+
+static inline int
 is_extern_subr_die (die)
      register dw_die_ref die;
 {
   register dw_attr_ref a;
   register int is_subr = FALSE;
   register int is_extern = FALSE;
+
   if (die != NULL && die->die_tag == DW_TAG_subprogram)
     {
       is_subr = TRUE;
@@ -2104,62 +2325,210 @@ is_extern_subr_die (die)
            }
        }
     }
+
   return is_subr && is_extern;
 }
 
-/* Return the "low pc" attribute value, typically associated with
-   a subprogram DIE.  Return null if the "low pc" attribute is
-   either not prsent, or if it cannot be represented as an
-   assembler label identifier.  */
-inline char *
-get_AT_low_pc (die)
+/* Get the attribute of type attr_kind.  */
+
+static inline dw_attr_ref
+get_AT (die, attr_kind)
      register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
 {
   register dw_attr_ref a;
-  register char *low_pc = NULL;
+  register dw_die_ref spec = NULL;
+  
   if (die != NULL)
     {
       for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
        {
-         if (a->dw_attr == DW_AT_low_pc
-             && a->dw_attr_val.val_class == dw_val_class_lbl_id)
-           {
-             low_pc = a->dw_attr_val.v.val_lbl_id;
-             break;
-           }
+         if (a->dw_attr == attr_kind)
+           return a;
+
+         if (a->dw_attr == DW_AT_specification
+             || a->dw_attr == DW_AT_abstract_origin)
+           spec = a->dw_attr_val.v.val_die_ref;
        }
+
+      if (spec)
+       return get_AT (spec, attr_kind);
     }
-  return low_pc;
+
+  return NULL;
 }
 
+/* Return the "low pc" attribute value, typically associated with
+   a subprogram DIE.  Return null if the "low pc" attribute is
+   either not prsent, or if it cannot be represented as an
+   assembler label identifier.  */
+
+static inline char *
+get_AT_low_pc (die)
+     register dw_die_ref die;
+{
+  register dw_attr_ref a = get_AT (die, DW_AT_low_pc);
+
+  if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
+    return a->dw_attr_val.v.val_lbl_id;
+
+  return NULL;
+}
 
 /* Return the "high pc" attribute value, typically associated with
    a subprogram DIE.  Return null if the "high pc" attribute is
    either not prsent, or if it cannot be represented as an
    assembler label identifier.  */
-inline char *
+
+static inline char *
 get_AT_hi_pc (die)
      register dw_die_ref die;
 {
+  register dw_attr_ref a = get_AT (die, DW_AT_high_pc);
+
+  if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
+    return a->dw_attr_val.v.val_lbl_id;
+
+  return NULL;
+}
+
+/* Return the value of the string attribute designated by ATTR_KIND, or
+   NULL if it is not present.  */
+
+static inline char *
+get_AT_string (die, attr_kind)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
+{
+  register dw_attr_ref a = get_AT (die, attr_kind);
+
+  if (a && a->dw_attr_val.val_class == dw_val_class_str)
+    return a->dw_attr_val.v.val_str;
+
+  return NULL;
+}
+
+/* Return the value of the flag attribute designated by ATTR_KIND, or -1
+   if it is not present.  */
+
+static inline int
+get_AT_flag (die, attr_kind)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
+{
+  register dw_attr_ref a = get_AT (die, attr_kind);
+
+  if (a && a->dw_attr_val.val_class == dw_val_class_flag)
+    return a->dw_attr_val.v.val_flag;
+
+  return -1;
+}
+
+/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
+   if it is not present.  */
+
+static inline unsigned
+get_AT_unsigned (die, attr_kind)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
+{
+  register dw_attr_ref a = get_AT (die, attr_kind);
+
+  if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const)
+    return a->dw_attr_val.v.val_unsigned;
+
+  return 0;
+}
+
+static inline int
+is_c_family ()
+{
+  register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+  return (lang == DW_LANG_C || lang == DW_LANG_C89
+         || lang == DW_LANG_C_plus_plus);
+} 
+
+static inline int
+is_fortran ()
+{
+  register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+  return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90);
+} 
+
+/* Remove the specified attribute if present.  */
+
+static inline void
+remove_AT (die, attr_kind)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
+{
   register dw_attr_ref a;
-  register char *hi_pc = NULL;
+  register dw_attr_ref removed = NULL;;
+
   if (die != NULL)
     {
-      for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+      if (die->die_attr->dw_attr == attr_kind)
        {
-         if (a->dw_attr == DW_AT_high_pc
-             && a->dw_attr_val.val_class == dw_val_class_lbl_id)
+         removed = die->die_attr;
+         if (die->die_attr_last == die->die_attr)
+           die->die_attr_last = NULL;
+
+         die->die_attr = die->die_attr->dw_attr_next;
+       }
+
+      else
+       for (a = die->die_attr; a->dw_attr_next != NULL;
+            a = a->dw_attr_next)
+         if (a->dw_attr_next->dw_attr == attr_kind)
            {
-             hi_pc = a->dw_attr_val.v.val_lbl_id;
+             removed = a->dw_attr_next;
+             if (die->die_attr_last == a->dw_attr_next)
+               die->die_attr_last = a;
+
+             a->dw_attr_next = a->dw_attr_next->dw_attr_next;
              break;
            }
+
+      if (removed != 0)
+       free (removed);
+    }
+}
+
+/* Discard the children of this DIE.  */
+
+static inline void
+remove_children (die)
+     register dw_die_ref die;
+{
+  register dw_die_ref child_die = die->die_child;
+
+  die->die_child = NULL;
+  die->die_child_last = NULL;
+
+  while (child_die != NULL)
+    {
+      register dw_die_ref tmp_die = child_die;
+      register dw_attr_ref a;
+
+      child_die = child_die->die_sib;
+      
+      for (a = tmp_die->die_attr; a != NULL; )
+       {
+         register dw_attr_ref tmp_a = a;
+
+         a = a->dw_attr_next;
+         free (tmp_a);
        }
+
+      free (tmp_die);
     }
-  return hi_pc;
 }
 
 /* Add a child DIE below its parent.  */
-inline void
+
+static inline void
 add_child_die (die, child_die)
      register dw_die_ref die;
      register dw_die_ref child_die;
@@ -2169,6 +2538,7 @@ add_child_die (die, child_die)
       assert (die != child_die);
       child_die->die_parent = die;
       child_die->die_sib = NULL;
+
       if (die->die_child == NULL)
        {
          die->die_child = child_die;
@@ -2183,80 +2553,65 @@ add_child_die (die, child_die)
 }
 
 /* Return a pointer to a newly created DIE node.  */
-inline dw_die_ref
+
+static inline dw_die_ref
 new_die (tag_value, parent_die)
      register enum dwarf_tag tag_value;
      register dw_die_ref parent_die;
 {
   register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node));
-  if (die != NULL)
-    {
-      die->die_tag = tag_value;
-      die->die_abbrev = 0;
-      die->die_offset = 0;
-      die->die_child = NULL;
-      die->die_parent = NULL;
-      die->die_sib = NULL;
-      die->die_child_last = NULL;
-      die->die_attr = NULL;
-      die->die_attr_last = NULL;
-      if (parent_die != NULL)
-       {
-         add_child_die (parent_die, die);
-       }
-    }
+
+  die->die_tag = tag_value;
+  die->die_abbrev = 0;
+  die->die_offset = 0;
+  die->die_child = NULL;
+  die->die_parent = NULL;
+  die->die_sib = NULL;
+  die->die_child_last = NULL;
+  die->die_attr = NULL;
+  die->die_attr_last = NULL;
+
+  if (parent_die != NULL)
+    add_child_die (parent_die, die);
+  else
+    ++limbo_die_count;
+
   return die;
 }
 
 /* Return the DIE associated with the given type specifier.  */
-inline dw_die_ref
+
+static inline dw_die_ref
 lookup_type_die (type)
      register tree type;
 {
-  register unsigned type_id = TYPE_UID (type);
-  return (type_id < type_die_table_in_use)
-    ? type_die_table[type_id] : NULL;
+  return (dw_die_ref) TYPE_SYMTAB_POINTER (type);
 }
 
 /* Equate a DIE to a given type specifier.  */
+
 static void
 equate_type_number_to_die (type, type_die)
      register tree type;
      register dw_die_ref type_die;
 {
-  register unsigned type_id = TYPE_UID (type);
-  register unsigned i;
-  register unsigned num_allocated;
-  if (type_id >= type_die_table_allocated)
-    {
-      num_allocated = (((type_id + 1)
-                       + TYPE_DIE_TABLE_INCREMENT - 1)
-                      / TYPE_DIE_TABLE_INCREMENT)
-       * TYPE_DIE_TABLE_INCREMENT;
-      type_die_table = (dw_die_ref *) xrealloc (type_die_table,
-                                      sizeof (dw_die_ref) * num_allocated);
-      bzero (&type_die_table[type_die_table_allocated],
-         (num_allocated - type_die_table_allocated) * sizeof (dw_die_ref));
-      type_die_table_allocated = num_allocated;
-    }
-  if (type_id >= type_die_table_in_use)
-    {
-      type_die_table_in_use = (type_id + 1);
-    }
-  type_die_table[type_id] = type_die;
+  TYPE_SYMTAB_POINTER (type) = (char *) type_die;
 }
 
 /* Return the DIE associated with a given declaration.  */
-inline dw_die_ref
+
+static inline dw_die_ref
 lookup_decl_die (decl)
      register tree decl;
 {
   register unsigned decl_id = DECL_UID (decl);
-  return (decl_id < decl_die_table_in_use)
-    ? decl_die_table[decl_id] : NULL;
+
+  return (decl_id < decl_die_table_in_use
+         ? decl_die_table[decl_id] : NULL);
 }
 
 /* Equate a DIE to a particular declaration.  */
+
 static void
 equate_decl_number_to_die (decl, decl_die)
      register tree decl;
@@ -2265,101 +2620,106 @@ equate_decl_number_to_die (decl, decl_die)
   register unsigned decl_id = DECL_UID (decl);
   register unsigned i;
   register unsigned num_allocated;
+
   if (decl_id >= decl_die_table_allocated)
     {
-      num_allocated = (((decl_id + 1)
-                       + DECL_DIE_TABLE_INCREMENT - 1)
-                      / DECL_DIE_TABLE_INCREMENT)
-       * DECL_DIE_TABLE_INCREMENT;
-      decl_die_table = (dw_die_ref *) xrealloc (decl_die_table,
-                                      sizeof (dw_die_ref) * num_allocated);
-      bzero (&decl_die_table[decl_die_table_allocated],
-         (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref));
+      num_allocated
+       = ((decl_id + 1 + DECL_DIE_TABLE_INCREMENT - 1)
+          / DECL_DIE_TABLE_INCREMENT)
+         * DECL_DIE_TABLE_INCREMENT;
+
+      decl_die_table
+       = (dw_die_ref *) xrealloc (decl_die_table,
+                                  sizeof (dw_die_ref) * num_allocated);
+
+      bzero ((char *) &decl_die_table[decl_die_table_allocated],
+            (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref));
       decl_die_table_allocated = num_allocated;
     }
+
   if (decl_id >= decl_die_table_in_use)
-    {
-      decl_die_table_in_use = (decl_id + 1);
-    }
+    decl_die_table_in_use = (decl_id + 1);
+
   decl_die_table[decl_id] = decl_die;
 }
 
 /* Return a pointer to a newly allocated location description.  Location
    descriptions are simple expression terms that can be strung
    together to form more complicated location (address) descriptions.  */
-inline dw_loc_descr_ref
+
+static inline dw_loc_descr_ref
 new_loc_descr (op, oprnd1, oprnd2)
      register enum dwarf_location_atom op;
      register unsigned long oprnd1;
      register unsigned long oprnd2;
 {
-  register dw_loc_descr_ref descr =
-  (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node));
-  if (descr != NULL)
-    {
-      descr->dw_loc_next = NULL;
-      descr->dw_loc_opc = op;
-      descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
-      descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
-      descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
-      descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
-    }
+  register dw_loc_descr_ref descr
+    = (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node));
+
+  descr->dw_loc_next = NULL;
+  descr->dw_loc_opc = op;
+  descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
+  descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
+  descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
+  descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
+
   return descr;
 }
 
 /* Add a location description term to a location description expression.  */
-inline void
+
+static inline void
 add_loc_descr (list_head, descr)
      register dw_loc_descr_ref *list_head;
      register dw_loc_descr_ref descr;
 {
   register dw_loc_descr_ref *d;
-  /* find the end of the chain.  */
+
+  /* Find the end of the chain.  */
   for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
-    {
-      /* nothing */ ;
-    }
+    ;
+
   *d = descr;
 }
 
 /* Return a pointer to a newly allocated Call Frame Instruction.  */
-inline dw_cfi_ref
+
+static inline dw_cfi_ref
 new_cfi ()
 {
   register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node));
-  if (cfi != NULL)
-    {
-      cfi->dw_cfi_next = NULL;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
-      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
-    }
+
+  cfi->dw_cfi_next = NULL;
+  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
+  cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
+
   return cfi;
 }
 
 /* Add a Call Frame Instruction to list of instructions.  */
-inline void
+
+static inline void
 add_cfi (list_head, cfi)
      register dw_cfi_ref *list_head;
      register dw_cfi_ref cfi;
 {
   register dw_cfi_ref *p;
-  /* find the end of the chain.  */
+
+  /* Find the end of the chain.  */
   for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
-    {
-      /* nothing */ ;
-    }
+    ;
+
   *p = cfi;
 }
 \f
-/********* Print DWARF Internal Representation (debugging aids) ***************/
-
 /* Keep track of the number of spaces used to indent the
    output of the debugging routines that print the structure of
    the DIE internal representation.  */
 static int print_indent;
 
 /* Indent the line the number of spaces given by print_indent.  */
-inline void
+
+static inline void
 print_spaces (outfile)
      FILE *outfile;
 {
@@ -2368,6 +2728,7 @@ print_spaces (outfile)
 
 /* Print the information assoaciated with a given DIE, and its children.
    This routine is a debugging aid only.  */
+
 static void
 print_die (die, outfile)
      dw_die_ref die;
@@ -2375,16 +2736,19 @@ print_die (die, outfile)
 {
   register dw_attr_ref a;
   register dw_die_ref c;
+
   print_spaces (outfile);
   fprintf (outfile, "DIE %4u: %s\n",
           die->die_offset, dwarf_tag_name (die->die_tag));
   print_spaces (outfile);
   fprintf (outfile, "  abbrev id: %u", die->die_abbrev);
   fprintf (outfile, " offset: %u\n", die->die_offset);
+
   for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
     {
       print_spaces (outfile);
       fprintf (outfile, "  %s: ", dwarf_attr_name (a->dw_attr));
+
       switch (a->dw_attr_val.val_class)
        {
        case dw_val_class_addr:
@@ -2399,24 +2763,23 @@ print_die (die, outfile)
        case dw_val_class_unsigned_const:
          fprintf (outfile, "%u", a->dw_attr_val.v.val_unsigned);
          break;
-       case dw_val_class_double_const:
+       case dw_val_class_long_long:
          fprintf (outfile, "constant (%u,%u)",
-                 a->dw_attr_val.v.val_dbl_const.dw_dbl_hi,
-                 a->dw_attr_val.v.val_dbl_const.dw_dbl_low);
+                 a->dw_attr_val.v.val_long_long.hi,
+                 a->dw_attr_val.v.val_long_long.low);
+         break;
+       case dw_val_class_float:
+         fprintf (outfile, "floating-point constant");
          break;
        case dw_val_class_flag:
          fprintf (outfile, "%u", a->dw_attr_val.v.val_flag);
          break;
        case dw_val_class_die_ref:
          if (a->dw_attr_val.v.val_die_ref != NULL)
-           {
-             fprintf (outfile, "die -> %u",
-                      a->dw_attr_val.v.val_die_ref->die_offset);
-           }
+           fprintf (outfile, "die -> %u",
+                    a->dw_attr_val.v.val_die_ref->die_offset);
          else
-           {
-             fprintf (outfile, "die -> <null>");
-           }
+           fprintf (outfile, "die -> <null>");
          break;
        case dw_val_class_lbl_id:
          fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id);
@@ -2426,36 +2789,35 @@ print_die (die, outfile)
          break;
        case dw_val_class_str:
          if (a->dw_attr_val.v.val_str != NULL)
-           {
-             fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str);
-           }
+           fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str);
          else
-           {
-             fprintf (outfile, "<null>");
-           }
+           fprintf (outfile, "<null>");
          break;
        }
+
       fprintf (outfile, "\n");
     }
+
   if (die->die_child != NULL)
     {
       print_indent += 4;
       for (c = die->die_child; c != NULL; c = c->die_sib)
-       {
-         print_die (c, outfile);
-       }
+       print_die (c, outfile);
+
       print_indent -= 4;
     }
 }
 
 /* Print the contents of the source code line number correspondence table.
    This routine is a debugging aid only.  */
+
 static void
 print_dwarf_line_table (outfile)
      FILE *outfile;
 {
   register unsigned i;
   register dw_line_info_ref line_info;
+
   fprintf (outfile, "\n\nDWARF source line information\n");
   for (i = 1; i < line_info_table_in_use; ++i)
     {
@@ -2465,10 +2827,12 @@ print_dwarf_line_table (outfile)
       fprintf (outfile, "%6d", line_info->dw_line_num);
       fprintf (outfile, "\n");
     }
+
   fprintf (outfile, "\n\n");
 }
 
 /* Print the information collected for a given DIE.  */
+
 void
 debug_dwarf_die (die)
      dw_die_ref die;
@@ -2476,8 +2840,9 @@ debug_dwarf_die (die)
   print_die (die, stderr);
 }
 
-/* Print all DWARF informaiton collected for the compilation unit.
+/* Print all DWARF information collected for the compilation unit.
    This routine is a debugging aid only.  */
+
 void
 debug_dwarf ()
 {
@@ -2485,13 +2850,11 @@ debug_dwarf ()
   print_die (comp_unit_die, stderr);
   print_dwarf_line_table (stderr);
 }
-
 \f
-/***************** DWARF Information Construction Support *********************/
-
 /* Traverse the DIE, and add a sibling attribute if it may have the
    effect of speeding up access to siblings.  To save some space,
    avoid generating sibling attributes for DIE's without children.  */
+
 static void
 add_sibling_attributes(die)
      register dw_die_ref die;
@@ -2501,25 +2864,21 @@ add_sibling_attributes(die)
   if (die != comp_unit_die && die->die_child != NULL)
     {
       attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-      if (attr != NULL)
-       {
-         attr->dw_attr_next = NULL;
-         attr->dw_attr = DW_AT_sibling;
-         attr->dw_attr_val.val_class = dw_val_class_die_ref;
-         attr->dw_attr_val.v.val_die_ref = die->die_sib;
-       }
-      /* add the sibling link to the front of the attribute list.  */
+      attr->dw_attr_next = NULL;
+      attr->dw_attr = DW_AT_sibling;
+      attr->dw_attr_val.val_class = dw_val_class_die_ref;
+      attr->dw_attr_val.v.val_die_ref = die->die_sib;
+
+      /* Add the sibling link to the front of the attribute list.  */
       attr->dw_attr_next = die->die_attr;
       if (die->die_attr == NULL)
-       {
-         die->die_attr_last = attr;
-       }
+       die->die_attr_last = attr;
+
       die->die_attr = attr;
     }
+
   for (c = die->die_child; c != NULL; c = c->die_sib)
-    {
-      add_sibling_attributes (c);
-    }
+    add_sibling_attributes (c);
 }
 
 /* The format of each DIE (and its attribute value pairs)
@@ -2527,6 +2886,7 @@ add_sibling_attributes(die)
    abbreviation table and assigns a unique abbreviation id for
    each abbreviation entry.  The children of each die are visited
    recursively.  */
+
 static void
 build_abbrev_table (die)
      register dw_die_ref die;
@@ -2538,62 +2898,63 @@ build_abbrev_table (die)
   for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
     {
       register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+
       if (abbrev->die_tag == die->die_tag)
        {
          if ((abbrev->die_child != NULL) == (die->die_child != NULL))
            {
              a_attr = abbrev->die_attr;
              d_attr = die->die_attr;
+
              while (a_attr != NULL && d_attr != NULL)
                {
                  if ((a_attr->dw_attr != d_attr->dw_attr)
-                     || (a_attr->dw_attr_val.val_class
-                         != d_attr->dw_attr_val.val_class))
-                   {
-                     break;
-                   }
+                     || (value_format (&a_attr->dw_attr_val)
+                         != value_format (&d_attr->dw_attr_val)))
+                   break;
+
                  a_attr = a_attr->dw_attr_next;
                  d_attr = d_attr->dw_attr_next;
                }
+
              if (a_attr == NULL && d_attr == NULL)
-               {
-                 break;
-               }
+               break;
            }
        }
     }
+
   if (abbrev_id >= abbrev_die_table_in_use)
     {
       if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
        {
          n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
-         abbrev_die_table = (dw_die_ref *)
-           xmalloc (abbrev_die_table,
-                    sizeof (dw_die_ref) * n_alloc);
-         bzero (&abbrev_die_table[abbrev_die_table_allocated],
-             (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
+         abbrev_die_table 
+           = (dw_die_ref *) xmalloc (abbrev_die_table,
+                                     sizeof (dw_die_ref) * n_alloc);
+
+         bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated],
+                (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
          abbrev_die_table_allocated = n_alloc;
        }
+
       ++abbrev_die_table_in_use;
       abbrev_die_table[abbrev_id] = die;
     }
+
   die->die_abbrev = abbrev_id;
   for (c = die->die_child; c != NULL; c = c->die_sib)
-    {
-      build_abbrev_table (c);
-    }
+    build_abbrev_table (c);
 }
-
 \f
-/**********************  DWARF Information Sizing *****************************/
-
 /* Return the size of an unsigned LEB128 quantity.  */
-inline unsigned long
+
+static inline unsigned long
 size_of_uleb128 (value)
      register unsigned long value;
 {
   register unsigned long size = 0;
   register unsigned byte;
+
   do
     {
       byte = (value & 0x7f);
@@ -2601,16 +2962,19 @@ size_of_uleb128 (value)
       size += 1;
     }
   while (value != 0);
+
   return size;
 }
 
 /* Return the size of a signed LEB128 quantity.  */
-inline unsigned long
+
+static inline unsigned long
 size_of_sleb128 (value)
      register long value;
 {
   register unsigned long size = 0;
   register unsigned byte;
+
   do
     {
       byte = (value & 0x7f);
@@ -2619,10 +2983,12 @@ size_of_sleb128 (value)
     }
   while (!(((value == 0) && ((byte & 0x40) == 0))
           || ((value == -1) && ((byte & 0x40) != 0))));
+
   return size;
 }
 
 /* Return the size of a string, including the null byte.  */
+
 static unsigned long
 size_of_string (str)
      register char *str;
@@ -2631,26 +2997,29 @@ size_of_string (str)
   register unsigned long slen = strlen (str);
   register unsigned long i;
   register unsigned c;
+
   for (i = 0; i < slen; ++i)
     {
       c = str[i];
       if (c == '\\')
-       {
-         ++i;
-       }
+       ++i;
+
       size += 1;
     }
+
   /* Null terminator.  */
   size += 1;
   return size;
 }
 
 /* Return the size of a location descriptor.  */
+
 static unsigned long
 size_of_loc_descr (loc)
      register dw_loc_descr_ref loc;
 {
   register unsigned long size = 1;
+
   switch (loc->dw_loc_opc)
     {
     case DW_OP_addr:
@@ -2742,58 +3111,97 @@ size_of_loc_descr (loc)
     default:
       break;
     }
+
+  return size;
+}
+
+/* Return the size of a series of location descriptors.  */
+
+static unsigned long
+size_of_locs (loc)
+     register dw_loc_descr_ref loc;
+{
+  register unsigned long size = 0;
+
+  for (; loc != NULL; loc = loc->dw_loc_next)
+    size += size_of_loc_descr (loc);
+
   return size;
 }
 
+/* Return the power-of-two number of bytes necessary to represent VALUE.  */
+
+static int
+constant_size (value)
+     long unsigned value;
+{
+  int log;
+
+  if (value == 0)
+    log = 0;
+  else
+    log = floor_log2 (value);
+
+  log = log / 8;
+  log = 1 << (floor_log2 (log) + 1);
+
+  return MIN (log, 4);
+}
+
 /* Return the size of a DIE, as it is represented in the
    .debug_info section.  */
+
 static unsigned long
 size_of_die (die)
      register dw_die_ref die;
 {
   register unsigned long size = 0;
   register dw_attr_ref a;
-  register dw_loc_descr_ref loc;
+
   size += size_of_uleb128 (die->die_abbrev);
   for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
     {
       switch (a->dw_attr_val.val_class)
        {
        case dw_val_class_addr:
-         size += 4;
+         size += PTR_SIZE;
          break;
        case dw_val_class_loc:
-         /* Block length.  */
-         size += 2;
-         for (loc = a->dw_attr_val.v.val_loc; loc != NULL;
-              loc = loc->dw_loc_next)
-           {
-             size += size_of_loc_descr (loc);
-           }
+         {
+           register unsigned long lsize
+             = size_of_locs (a->dw_attr_val.v.val_loc);
+
+           /* Block length.  */
+           size += constant_size (lsize);
+           size += lsize;
+         }
          break;
        case dw_val_class_const:
          size += 4;
          break;
        case dw_val_class_unsigned_const:
-         size += 4;
+         size += constant_size (a->dw_attr_val.v.val_unsigned);
+         break;
+       case dw_val_class_long_long:
+         size += 1 + 8; /* block */
          break;
-       case dw_val_class_double_const:
-         size += 8;
+       case dw_val_class_float:
+         size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */
          break;
        case dw_val_class_flag:
          size += 1;
          break;
        case dw_val_class_die_ref:
-         size += 4;
+         size += DWARF_OFFSET_SIZE;
          break;
        case dw_val_class_fde_ref:
-         size += 4;
+         size += DWARF_OFFSET_SIZE;
          break;
        case dw_val_class_lbl_id:
-         size += 4;
+         size += PTR_SIZE;
          break;
        case dw_val_class_section_offset:
-         size += 4;
+         size += DWARF_OFFSET_SIZE;
          break;
        case dw_val_class_str:
          size += size_of_string (a->dw_attr_val.v.val_str);
@@ -2802,6 +3210,7 @@ size_of_die (die)
          abort ();
        }
     }
+
   return size;
 }
 
@@ -2810,52 +3219,57 @@ size_of_die (die)
    variable next_die_offset, on each time through.  Uses the
    current value of next_die_offset to updete the die_offset
    field in each DIE.  */
+
 static void
 calc_die_sizes (die)
      dw_die_ref die;
 {
   register dw_die_ref c;
-  register unsigned long die_size;
   die->die_offset = next_die_offset;
   next_die_offset += size_of_die (die);
+
   for (c = die->die_child; c != NULL; c = c->die_sib)
-    {
-      calc_die_sizes (c);
-    }
+    calc_die_sizes (c);
+
   if (die->die_child != NULL)
-    {
-      /* Count the null byte used to terminate sibling lists.  */
-      next_die_offset += 1;
-    }
+    /* Count the null byte used to terminate sibling lists.  */
+    next_die_offset += 1;
 }
 
 /* Return the size of the line information prolog generated for the
    compilation unit.  */
+
 static unsigned long
 size_of_line_prolog ()
 {
   register unsigned long size;
-  register unsigned opc;
-  register unsigned n_op_args;
   register unsigned long ft_index;
+
   size = DWARF_LINE_PROLOG_HEADER_SIZE;
+
   /* Count the size of the table giving number of args for each
      standard opcode.  */
   size += DWARF_LINE_OPCODE_BASE - 1;
+
   /* Include directory table is empty (at present).  Count only the
      the null byte used to terminate the table.  */
   size += 1;
+
   for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
     {
       /* File name entry.  */
       size += size_of_string (file_table[ft_index]);
+
       /* Include directory index.  */
       size += size_of_uleb128 (0);
+
       /* Modification time.  */
       size += size_of_uleb128 (0);
+
       /* File length in bytes.  */
       size += size_of_uleb128 (0);
     }
+
   /* Count the file table terminator.  */
   size += 1;
   return size;
@@ -2863,29 +3277,36 @@ size_of_line_prolog ()
 
 /* Return the size of the line information generated for this
    compilation unit.  */
+
 static unsigned long
 size_of_line_info ()
 {
   register unsigned long size;
-  register dw_line_info_ref line_info;
   register unsigned long lt_index;
   register unsigned long current_line;
   register long line_offset;
   register long line_delta;
   register unsigned long current_file;
+  register unsigned long function;
+
   /* Version number.  */
   size = 2;
+
   /* Prolog length specifier.  */
-  size += 4;
+  size += DWARF_OFFSET_SIZE;
+
   /* Prolog.  */
   size += size_of_line_prolog ();
+
   /* Set address register instruction.  */
-  size += 1 + size_of_uleb128 (1 + PTR_SIZE)
-    + 1 + PTR_SIZE;
+  size += 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE;
+
   current_file = 1;
   current_line = 1;
   for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
     {
+      register dw_line_info_ref line_info;
+
       /* Advance pc instruction.  */
       size += 1 + 2;
       line_info = &line_info_table[lt_index];
@@ -2896,104 +3317,171 @@ size_of_line_info ()
          current_file = line_info->dw_file_num;
          size += size_of_uleb128 (current_file);
        }
+
       if (line_info->dw_line_num != current_line)
        {
          line_offset = line_info->dw_line_num - current_line;
          line_delta = line_offset - DWARF_LINE_BASE;
          current_line = line_info->dw_line_num;
          if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+           /* 1-byte special line number instruction.  */
+           size += 1;
+         else
            {
-             /* 1-byte special line number instruction.  */
+             /* Advance line instruction.  */
+             size += 1;
+             size += size_of_sleb128 (line_offset);
+             /* Generate line entry instruction.  */
              size += 1;
            }
+       }
+    }
+
+  /* Advance pc instruction.  */
+  size += 1 + 2;
+
+  /* End of line number info. marker.  */
+  size += 1 + size_of_uleb128 (1) + 1;
+
+  function = 0;
+  current_file = 1;
+  current_line = 1;
+  for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
+    {
+      register dw_separate_line_info_ref line_info
+       = &separate_line_info_table[lt_index];
+      if (function != line_info->function)
+       {
+         function = line_info->function;
+         /* Set address register instruction.  */
+         size += 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE;
+       }
+      else
+       /* Advance pc instruction.  */
+       size += 1 + 2;
+
+      if (line_info->dw_file_num != current_file)
+       {
+         /* Set file number instruction.  */
+         size += 1;
+         current_file = line_info->dw_file_num;
+         size += size_of_uleb128 (current_file);
+       }
+
+      if (line_info->dw_line_num != current_line)
+       {
+         line_offset = line_info->dw_line_num - current_line;
+         line_delta = line_offset - DWARF_LINE_BASE;
+         current_line = line_info->dw_line_num;
+         if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+           /* 1-byte special line number instruction.  */
+           size += 1;
          else
            {
              /* Advance line instruction.  */
              size += 1;
              size += size_of_sleb128 (line_offset);
+
              /* Generate line entry instruction.  */
              size += 1;
            }
        }
+
+      ++lt_index;
+
+      /* If we're done with a function, end its sequence.  */
+      if (lt_index == separate_line_info_table_in_use
+         || separate_line_info_table[lt_index].function != function)
+       {
+         current_file = 1;
+         current_line = 1;
+
+         /* Advance pc instruction.  */
+         size += 1 + 2;
+
+         /* End of line number info. marker.  */
+         size += 1 + size_of_uleb128 (1) + 1;
+       }
     }
-  /* Set address register instruction.  */
-  size += 1 + size_of_uleb128 (1 + PTR_SIZE)
-    + 1 + PTR_SIZE;
-  /* End of line number info. marker.  */
-  size += 1 + size_of_uleb128 (1) + 1;
+
   return size;
 }
 
 /* Return the size of the .debug_pubnames table  generated for the
    compilation unit.  */
+
 static unsigned long
 size_of_pubnames ()
 {
-  dw_die_ref die;
   register unsigned long size;
+  register unsigned i;
+
   size = DWARF_PUBNAMES_HEADER_SIZE;
-  for (die = comp_unit_die->die_child; die != NULL; die = die->die_sib)
+  for (i = 0; i < pubname_table_in_use; ++i)
     {
-      if (is_extern_subr_die (die))
-       {
-         char *low_pc = get_AT_low_pc (die);
-         if (low_pc != NULL)
-           {
-             size += 4;
-             size += size_of_string (low_pc);
-           }
-       }
+      register pubname_ref p = &pubname_table[i];
+      size += DWARF_OFFSET_SIZE + size_of_string (p->name);
     }
-  size += 4;
+
+  size += DWARF_OFFSET_SIZE;
   return size;
 }
 
 /* Return the size of the information in the .debug_aranges seciton.  */
+
 static unsigned long
 size_of_aranges ()
 {
   register unsigned long size;
+
   size = DWARF_ARANGES_HEADER_SIZE;
+
   /* Count the address/length pair for this compilation unit.  */
-  size += 8;
+  size += 2 * PTR_SIZE;
+  size += 2 * PTR_SIZE * arange_table_in_use;
+
   /* Count the two zero words used to terminated the address range table.  */
-  size += 8;
+  size += 2 * PTR_SIZE;
   return size;
 }
 \f
-/**************** DWARF Debug Information Output *****************************/
-
 /* Output an unsigned LEB128 quantity.  */
+
 static void
 output_uleb128 (value)
      register unsigned long value;
 {
+  unsigned long save_value = value;
+
   fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
   do
     {
       register unsigned byte = (value & 0x7f);
       value >>= 7;
       if (value != 0)
-       {
-         /* More bytes to follow.  */
-         byte |= 0x80;
-       }
+       /* More bytes to follow.  */
+       byte |= 0x80;
+
       fprintf (asm_out_file, "0x%x", byte);
       if (value != 0)
-       {
-         fprintf (asm_out_file, ",");
-       }
+       fprintf (asm_out_file, ",");
     }
   while (value != 0);
+
+  if (flag_verbose_asm)
+    fprintf (asm_out_file, "\t%s ULEB128 0x%x", ASM_COMMENT_START, save_value);
 }
 
 /* Output an signed LEB128 quantity.  */
+
 static void
 output_sleb128 (value)
      register long value;
 {
   register int more;
   register unsigned byte;
+  long save_value = value;
+
   fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
   do
     {
@@ -3003,130 +3491,150 @@ output_sleb128 (value)
       more = !((((value == 0) && ((byte & 0x40) == 0))
                || ((value == -1) && ((byte & 0x40) != 0))));
       if (more)
-       {
-         byte |= 0x80;
-       }
+       byte |= 0x80;
+
       fprintf (asm_out_file, "0x%x", byte);
       if (more)
-       {
-         fprintf (asm_out_file, ",");
-       }
+       fprintf (asm_out_file, ",");
     }
+
   while (more);
+  if (flag_verbose_asm)
+    fprintf (asm_out_file, "\t%s SLEB128 %d", ASM_COMMENT_START, save_value);
 }
 
-/* Output the encoding of an attribute value.  */
-static void
-output_value_format (v)
+/* Select the encoding of an attribute value.  */
+
+static enum dwarf_form
+value_format (v)
      dw_val_ref v;
 {
-  enum dwarf_form form;
   switch (v->val_class)
     {
     case dw_val_class_addr:
-      form = DW_FORM_addr;
-      break;
+      return DW_FORM_addr;
     case dw_val_class_loc:
-      form = DW_FORM_block2;
-      break;
+      switch (constant_size (size_of_locs (v->v.val_loc)))
+       {
+       case 1:
+         return DW_FORM_block1;
+       case 2:
+         return DW_FORM_block2;
+       default:
+         abort ();
+       }
     case dw_val_class_const:
-      form = DW_FORM_data4;
-      break;
+      return DW_FORM_data4;
     case dw_val_class_unsigned_const:
-      form = DW_FORM_data4;
-      break;
-    case dw_val_class_double_const:
-      form = DW_FORM_data8;
-      break;
+      switch (constant_size (v->v.val_unsigned))
+       {
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         return DW_FORM_data4;
+       case 8:
+         return DW_FORM_data8;
+       default:
+         abort ();
+       }
+    case dw_val_class_long_long:
+      return DW_FORM_block1;
+    case dw_val_class_float:
+      return DW_FORM_block1;
     case dw_val_class_flag:
-      form = DW_FORM_flag;
-      break;
+      return DW_FORM_flag;
     case dw_val_class_die_ref:
-      form = DW_FORM_ref4;
-      break;
+      return DW_FORM_ref;
     case dw_val_class_fde_ref:
-      form = DW_FORM_data4;
-      break;
+      return DW_FORM_data;
     case dw_val_class_lbl_id:
-      form = DW_FORM_addr;
-      break;
+      return DW_FORM_addr;
     case dw_val_class_section_offset:
-      form = DW_FORM_data4;
-      break;
+      return DW_FORM_data;
     case dw_val_class_str:
-      form = DW_FORM_string;
-      break;
+      return DW_FORM_string;
     default:
       abort ();
     }
+}
+
+/* Output the encoding of an attribute value.  */
+
+static void
+output_value_format (v)
+     dw_val_ref v;
+{
+  enum dwarf_form form = value_format (v);
+
   output_uleb128 (form);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s %s",
-              ASM_COMMENT_START, dwarf_form_name (form));
-    }
+    fprintf (asm_out_file, " (%s)", dwarf_form_name (form));
+
   fputc ('\n', asm_out_file);
 }
 
 /* Output the .debug_abbrev section which defines the DIE abbreviation
    table.  */
+
 static void
 output_abbrev_section ()
 {
   unsigned long abbrev_id;
+
   dw_attr_ref a_attr;
   for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
     {
       register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+
       output_uleb128 (abbrev_id);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s abbrev code = %u",
-                  ASM_COMMENT_START, abbrev_id);
-       }
+       fprintf (asm_out_file, " (abbrev code)");
+
       fputc ('\n', asm_out_file);
       output_uleb128 (abbrev->die_tag);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s TAG: %s",
-                  ASM_COMMENT_START, dwarf_tag_name (abbrev->die_tag));
-       }
+       fprintf (asm_out_file, " (TAG: %s)",
+                dwarf_tag_name (abbrev->die_tag));
+
       fputc ('\n', asm_out_file);
       fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP,
-              (abbrev->die_child != NULL)
-              ? DW_children_yes : DW_children_no);
+              abbrev->die_child != NULL ? DW_children_yes : DW_children_no);
+
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s %s",
-                  ASM_COMMENT_START,
-                  (abbrev->die_child != NULL)
-                  ? "DW_children_yes" : "DW_children_no");
-       }
+       fprintf (asm_out_file, "\t%s %s",
+                ASM_COMMENT_START,
+                (abbrev->die_child != NULL
+                 ? "DW_children_yes" : "DW_children_no"));
+
       fputc ('\n', asm_out_file);
+
       for (a_attr = abbrev->die_attr; a_attr != NULL;
           a_attr = a_attr->dw_attr_next)
        {
          output_uleb128 (a_attr->dw_attr);
          if (flag_verbose_asm)
-           {
-             fprintf (asm_out_file, "\t%s %s",
-                      ASM_COMMENT_START,
-                      dwarf_attr_name (a_attr->dw_attr));
-           }
+           fprintf (asm_out_file, " (%s)",
+                    dwarf_attr_name (a_attr->dw_attr));
+
          fputc ('\n', asm_out_file);
          output_value_format (&a_attr->dw_attr_val);
        }
+
       fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP);
     }
 }
 
 /* Output location description stack opcode's operands (if any).  */
+
 static void
 output_loc_operands (loc)
      register dw_loc_descr_ref loc;
 {
   register dw_val_ref val1 = &loc->dw_loc_oprnd1;
   register dw_val_ref val2 = &loc->dw_loc_oprnd2;
+
   switch (loc->dw_loc_opc)
     {
     case DW_OP_addr:
@@ -3150,9 +3658,7 @@ output_loc_operands (loc)
       break;
     case DW_OP_const8u:
     case DW_OP_const8s:
-      ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
-                             val1->v.val_dbl_const.dw_dbl_hi,
-                             val2->v.val_dbl_const.dw_dbl_low);
+      abort ();
       fputc ('\n', asm_out_file);
       break;
     case DW_OP_constu:
@@ -3160,7 +3666,7 @@ output_loc_operands (loc)
       fputc ('\n', asm_out_file);
       break;
     case DW_OP_consts:
-      output_sleb128 (val1->v.val_unsigned);
+      output_sleb128 (val1->v.val_int);
       fputc ('\n', asm_out_file);
       break;
     case DW_OP_pick:
@@ -3216,13 +3722,13 @@ output_loc_operands (loc)
       fputc ('\n', asm_out_file);
       break;
     case DW_OP_fbreg:
-      output_sleb128 (val1->v.val_unsigned);
+      output_sleb128 (val1->v.val_int);
       fputc ('\n', asm_out_file);
       break;
     case DW_OP_bregx:
       output_uleb128 (val1->v.val_unsigned);
       fputc ('\n', asm_out_file);
-      output_sleb128 (val2->v.val_unsigned);
+      output_sleb128 (val2->v.val_int);
       fputc ('\n', asm_out_file);
       break;
     case DW_OP_piece:
@@ -3240,24 +3746,24 @@ output_loc_operands (loc)
 }
 
 /* Compute the offset of a sibling.  */
+
 static unsigned long
 sibling_offset (die)
      dw_die_ref die;
 {
   unsigned long offset;
+
   if (die->die_child_last == NULL)
-    {
-      offset = die->die_offset + size_of_die (die);
-    }
+    offset = die->die_offset + size_of_die (die);
   else
-    {
-      offset = sibling_offset (die->die_child_last) + 1;
-    }
+    offset = sibling_offset (die->die_child_last) + 1;
+
   return offset;
 }
 
 /* Output the DIE and its attributes.  Called recursively to generate
    the definitions of each child DIE.  */
+
 static void
 output_die (die)
      register dw_die_ref die;
@@ -3267,15 +3773,15 @@ output_die (die)
   register unsigned long ref_offset;
   register unsigned long size;
   register dw_loc_descr_ref loc;
+  register int i;
+
   output_uleb128 (die->die_abbrev);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s DIE (0x%x) %s",
-              ASM_COMMENT_START,
-              die->die_offset,
-              dwarf_tag_name (die->die_tag));
-    }
+    fprintf (asm_out_file, " (DIE (0x%x) %s)",
+            die->die_offset, dwarf_tag_name (die->die_tag));
+
   fputc ('\n', asm_out_file);
+
   for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
     {
       switch (a->dw_attr_val.val_class)
@@ -3284,20 +3790,27 @@ output_die (die)
          ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file,
                                       a->dw_attr_val.v.val_addr);
          break;
+
        case dw_val_class_loc:
-         size = 0;
-         for (loc = a->dw_attr_val.v.val_loc; loc != NULL;
-              loc = loc->dw_loc_next)
-           {
-             size += size_of_loc_descr (loc);
-           }
+         size = size_of_locs (a->dw_attr_val.v.val_loc);
+
          /* Output the block length for this list of location operations.  */
-         ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size);
-         if (flag_verbose_asm)
+         switch (constant_size (size))
            {
-             fprintf (asm_out_file, "\t%s %s",
-                      ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+           case 1:
+             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size);
+             break;
+           case 2:
+             ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size);
+             break;
+           default:
+             abort ();
            }
+
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s %s",
+                    ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+
          fputc ('\n', asm_out_file);
          for (loc = a->dw_attr_val.v.val_loc; loc != NULL;
               loc = loc->dw_loc_next)
@@ -3305,136 +3818,580 @@ output_die (die)
              /* Output the opcode.  */
              ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc);
              if (flag_verbose_asm)
-               {
-                 fprintf (asm_out_file, "\t%s %s",
-                          ASM_COMMENT_START,
-                          dwarf_stack_op_name (loc->dw_loc_opc));
-               }
+               fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
+                        dwarf_stack_op_name (loc->dw_loc_opc));
+
              fputc ('\n', asm_out_file);
+
              /* Output the operand(s) (if any).  */
              output_loc_operands (loc);
            }
          break;
+
        case dw_val_class_const:
          ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int);
          break;
+
        case dw_val_class_unsigned_const:
-         ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_unsigned);
+         switch (constant_size (a->dw_attr_val.v.val_unsigned))
+           {
+           case 1:
+             ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+                                     a->dw_attr_val.v.val_unsigned);
+             break;
+           case 2:
+             ASM_OUTPUT_DWARF_DATA2 (asm_out_file,
+                                     a->dw_attr_val.v.val_unsigned);
+             break;
+           case 4:
+             ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
+                                     a->dw_attr_val.v.val_unsigned);
+             break;
+           default:
+             abort ();
+           }
          break;
-       case dw_val_class_double_const:
+
+       case dw_val_class_long_long:
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s %s",
+                  ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+
+         fputc ('\n', asm_out_file);
          ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
-                                 a->dw_attr_val.v.val_dbl_const.dw_dbl_hi,
-                                 a->dw_attr_val.v.val_dbl_const.dw_dbl_low);
+                                 a->dw_attr_val.v.val_long_long.hi,
+                                 a->dw_attr_val.v.val_long_long.low);
+
+         if (flag_verbose_asm)
+           fprintf (asm_out_file,
+                    "\t%s long long constant", ASM_COMMENT_START);
+         
+         fputc ('\n', asm_out_file);
+         break;
+
+       case dw_val_class_float:
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+                                 a->dw_attr_val.v.val_float.length * 4);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s %s",
+                    ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+
+         fputc ('\n', asm_out_file);
+         for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i)
+           {
+             ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
+                                     a->dw_attr_val.v.val_float.array[i]);
+             if (flag_verbose_asm)
+               fprintf (asm_out_file, "\t%s fp constant word %d",
+                        ASM_COMMENT_START, i);
+
+             fputc ('\n', asm_out_file);
+           }
          break;
+
        case dw_val_class_flag:
          ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag);
          break;
+
        case dw_val_class_die_ref:
          if (a->dw_attr_val.v.val_die_ref != NULL)
-           {
-             ref_offset = a->dw_attr_val.v.val_die_ref->die_offset;
-           }
+           ref_offset = a->dw_attr_val.v.val_die_ref->die_offset;
          else if (a->dw_attr == DW_AT_sibling)
-           {
-             ref_offset = sibling_offset(die);
-           }
+           ref_offset = sibling_offset(die);
          else
-           {
-             abort ();
-           }
-         ASM_OUTPUT_DWARF_DATA4 (asm_out_file, ref_offset);
+           abort ();
+
+         ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset);
          break;
+
        case dw_val_class_fde_ref:
          ref_offset = fde_table[a->dw_attr_val.v.val_fde_index].dw_fde_offset;
-         fprintf (asm_out_file, "\t%s\t%s+0x%x", UNALIGNED_INT_ASM_OP,
+         fprintf (asm_out_file, "\t%s\t%s+0x%x", UNALIGNED_OFFSET_ASM_OP,
                   stripattributes (FRAME_SECTION), ref_offset);
          break;
+
        case dw_val_class_lbl_id:
          ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id);
          break;
+
        case dw_val_class_section_offset:
-         ASM_OUTPUT_DWARF_ADDR (asm_out_file,
-                                stripattributes (a->dw_attr_val.v.val_section));
+         ASM_OUTPUT_DWARF_OFFSET (asm_out_file,
+                                  stripattributes
+                                  (a->dw_attr_val.v.val_section));
          break;
+
        case dw_val_class_str:
          ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str);
          break;
+
        default:
          abort ();
        }
-      if (a->dw_attr_val.val_class != dw_val_class_loc)
+
+      if (a->dw_attr_val.val_class != dw_val_class_loc
+         && a->dw_attr_val.val_class != dw_val_class_long_long
+         && a->dw_attr_val.val_class != dw_val_class_float)
        {
          if (flag_verbose_asm)
-           {
-             fprintf (asm_out_file, "\t%s %s",
-                      ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
-           }
+           fprintf (asm_out_file, "\t%s %s",
+                    ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+
          fputc ('\n', asm_out_file);
        }
     }
+
   for (c = die->die_child; c != NULL; c = c->die_sib)
-    {
-      output_die (c);
-    }
+    output_die (c);
+
   if (die->die_child != NULL)
     {
       /* Add null byte to terminate sibling list. */
       ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+      if (flag_verbose_asm)
+       fprintf (asm_out_file, "\t%s end of children of DIE 0x%x",
+                ASM_COMMENT_START, die->die_offset);
+
       fputc ('\n', asm_out_file);
     }
 }
 
 /* Output the compilation unit that appears at the beginning of the
    .debug_info section, and precedes the DIE descriptions.  */
+
 static void
 output_compilation_unit_header ()
 {
-  /* ??? The dwarf standard says this must be a 4 byte integer, but the
-     SGI dwarf reader assumes this is the same size as a pointer.  */
-  fprintf (asm_out_file, "\t%s\t0x%x",
-          UNALIGNED_INT_ASM_OP, next_die_offset - 4);
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
-  fprintf (asm_out_file, "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, DWARF_VERSION);
+  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s DWARF version number",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
-  fprintf (asm_out_file, "\t%s\t%s", UNALIGNED_INT_ASM_OP,
-          stripattributes (ABBREV_SECTION));
+  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (ABBREV_SECTION));
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
-  fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, PTR_SIZE);
+  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
   if (flag_verbose_asm)
+    fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START);
+
+  fputc ('\n', asm_out_file);
+}
+
+/* Generate a new label for the CFI info to refer to.  */
+
+static char *
+dwarf2out_cfi_label ()
+{
+  static char label[20];
+  static unsigned long label_num = 0;
+  
+  ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++);
+  ASM_OUTPUT_LABEL (asm_out_file, label);
+
+  return label;
+}
+
+/* Add CFI to the current fde at the PC value indicated by LABEL if specified,
+   or to the CIE if LABEL is NULL.  */
+
+static void
+add_fde_cfi (label, cfi)
+     register char *label;
+     register dw_cfi_ref cfi;
+{
+  if (label)
     {
-      fprintf (asm_out_file, "\t%s Pointer Size (in bytes)",
-              ASM_COMMENT_START);
+      register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+
+      if (*label == 0)
+       label = dwarf2out_cfi_label ();
+
+      if (fde->dw_fde_current_label == NULL
+         || strcmp (label, fde->dw_fde_current_label) != 0)
+       {
+         register dw_cfi_ref xcfi;
+
+         fde->dw_fde_current_label = label = xstrdup (label);
+
+         /* Set the location counter to the new label.  */
+         xcfi = new_cfi ();
+         xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
+         xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
+         add_cfi (&fde->dw_fde_cfi, xcfi);
+       }
+
+      add_cfi (&fde->dw_fde_cfi, cfi);
+    }
+
+  else
+    add_cfi (&cie_cfi_head, cfi);
+}
+
+/* Subroutine of lookup_cfa.  */
+
+static inline void
+lookup_cfa_1 (cfi, regp, offsetp)
+     register dw_cfi_ref cfi;
+     register unsigned long *regp;
+     register long *offsetp;
+{
+  switch (cfi->dw_cfi_opc)
+    {
+    case DW_CFA_def_cfa_offset:
+      *offsetp = cfi->dw_cfi_oprnd1.dw_cfi_offset;
+      break;
+    case DW_CFA_def_cfa_register:
+      *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+      break;
+    case DW_CFA_def_cfa:
+      *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+      *offsetp = cfi->dw_cfi_oprnd2.dw_cfi_offset;
+      break;
+    }
+}
+
+/* Find the previous value for the CFA.  */
+
+static void
+lookup_cfa (regp, offsetp)
+     register unsigned long *regp;
+     register long *offsetp;
+{
+  register dw_cfi_ref cfi;
+
+  *regp = (unsigned long) -1;
+  *offsetp = 0;
+
+  for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
+    lookup_cfa_1 (cfi, regp, offsetp);
+
+  if (fde_table_in_use)
+    {
+      register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+      for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
+       lookup_cfa_1 (cfi, regp, offsetp);
+    }
+}
+
+/* Entry point to update the canonical frame address (CFA).
+   LABEL is passed to add_fde_cfi.  The value of CFA is now to be
+   calculated from REG+OFFSET.  */
+
+void
+dwarf2out_def_cfa (label, reg, offset)
+     register char *label;
+     register unsigned reg;
+     register long offset;
+{
+  register dw_cfi_ref cfi;
+  unsigned long old_reg;
+  long old_offset;
+
+  reg = DWARF_FRAME_REGNUM (reg);
+  lookup_cfa (&old_reg, &old_offset);
+
+  if (reg == old_reg && offset == old_offset)
+    return;
+
+  cfi = new_cfi ();
+
+  if (reg == old_reg)
+    {
+      cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
+      cfi->dw_cfi_oprnd1.dw_cfi_offset = offset;
+    }
+
+#ifndef MIPS_DEBUGGING_INFO  /* SGI dbx thinks this means no offset.  */
+  else if (offset == old_offset && old_reg != (unsigned long) -1)
+    {
+      cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+    }
+#endif
+
+  else
+    {
+      cfi->dw_cfi_opc = DW_CFA_def_cfa;
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+      cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
+    }
+
+  add_fde_cfi (label, cfi);
+}
+
+/* Add the CFI for saving a register.  REG is the CFA column number.
+   LABEL is passed to add_fde_cfi.
+   If SREG is -1, the register is saved at OFFSET from the CFA;
+   otherwise it is saved in SREG.  */
+
+static void
+reg_save (label, reg, sreg, offset)
+     register char * label;
+     register unsigned reg;
+     register unsigned sreg;
+     register long offset;
+{
+  register dw_cfi_ref cfi = new_cfi ();
+
+  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+
+  if (sreg == -1)
+    {
+      if (reg & ~0x3f)
+       /* The register number won't fit in 6 bits, so we have to use
+          the long form.  */
+       cfi->dw_cfi_opc = DW_CFA_offset_extended;
+      else
+       cfi->dw_cfi_opc = DW_CFA_offset;
+
+      offset /= DWARF_CIE_DATA_ALIGNMENT;
+      assert (offset >= 0);
+      cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
+    }
+  else
+    {
+      cfi->dw_cfi_opc = DW_CFA_register;
+      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
+    }
+
+  add_fde_cfi (label, cfi);
+}
+
+/* Entry point for saving a register.  REG is the GCC register number.
+   LABEL and OFFSET are passed to reg_save.  */
+
+void
+dwarf2out_reg_save (label, reg, offset)
+     register char * label;
+     register unsigned reg;
+     register long offset;
+{
+  reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset);
+}
+
+/* Record the initial position of the return address.  RTL is
+   INCOMING_RETURN_ADDR_RTX.  */
+
+static void
+initial_return_save (rtl)
+     register rtx rtl;
+{
+  unsigned reg = -1;
+  long offset = 0;
+
+  switch (GET_CODE (rtl))
+    {
+    case REG:
+      /* RA is in a register.  */
+      reg = reg_number (rtl);
+      break;
+    case MEM:
+      /* RA is on the stack.  */
+      rtl = XEXP (rtl, 0);
+      switch (GET_CODE (rtl))
+       {
+       case REG:
+         assert (REGNO (rtl) == STACK_POINTER_REGNUM);
+         offset = 0;
+         break;
+       case PLUS:
+         assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
+         offset = INTVAL (XEXP (rtl, 1));
+         break;
+       case MINUS:
+         assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
+         offset = -INTVAL (XEXP (rtl, 1));
+         break;
+       default:
+         abort ();
+       }
+      break;
+    default:
+      abort ();
+    }
+
+  reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset);
+}
+
+/* Record call frame debugging information for INSN, which either
+   sets SP or FP (adjusting how we calculate the frame address) or saves a
+   register to the stack.  If INSN is NULL_RTX, initialize our state.  */
+
+void
+dwarf2out_frame_debug (insn)
+     rtx insn;
+{
+  char *label;
+  rtx src, dest;
+  long offset;
+
+  /* The current rule for calculating the DWARF2 canonical frame address.  */
+  static unsigned cfa_reg;
+  static long cfa_offset;
+
+  /* The register used for saving registers to the stack, and its offset
+     from the CFA.  */
+  static unsigned cfa_store_reg;
+  static long cfa_store_offset;
+
+  /* A temporary register used in adjusting SP or setting up the store_reg.  */
+  static unsigned cfa_temp_reg;
+  static long cfa_temp_value;
+
+  if (insn == NULL_RTX)
+    {
+      /* Set up state for generating call frame debug info.  */
+      cfa_reg = STACK_POINTER_REGNUM;
+      cfa_offset = 0;
+      cfa_store_reg = STACK_POINTER_REGNUM;
+      cfa_store_offset = 0;
+      cfa_temp_reg = -1;
+      cfa_temp_value = 0;
+      return;
+    }
+
+  label = dwarf2out_cfi_label ();
+    
+  insn = PATTERN (insn);
+  assert (GET_CODE (insn) == SET);
+
+  src = SET_SRC (insn);
+  dest = SET_DEST (insn);
+
+  switch (GET_CODE (dest))
+    {
+    case REG:
+      /* Update the CFA rule wrt SP or FP.  Make sure src is
+        relative to the current CFA register.  */
+      switch (GET_CODE (src))
+       {
+         /* Setting FP from SP.  */
+       case REG:
+         assert (cfa_reg == REGNO (src));
+         assert (REGNO (dest) == STACK_POINTER_REGNUM
+                 || (frame_pointer_needed
+                     && REGNO (dest) == HARD_FRAME_POINTER_REGNUM));
+         cfa_reg = REGNO (dest);
+         break;
+
+       case PLUS:
+       case MINUS:
+         if (dest == stack_pointer_rtx)
+           {
+             /* Adjusting SP.  */
+             switch (GET_CODE (XEXP (src, 1)))
+               {
+               case CONST_INT:
+                 offset = INTVAL (XEXP (src, 1));
+                 break;
+               case REG:
+                 assert (REGNO (XEXP (src, 1)) == cfa_temp_reg);
+                 offset = cfa_temp_value;
+                 break;
+               default:
+                 abort ();
+               }
+
+             if (GET_CODE (src) == PLUS)
+               offset = -offset;
+             if (cfa_reg == STACK_POINTER_REGNUM)
+               cfa_offset += offset;
+             if (cfa_store_reg == STACK_POINTER_REGNUM)
+               cfa_store_offset += offset;
+             assert (XEXP (src, 0) == stack_pointer_rtx);
+           }
+         else
+           {
+             /* Initializing the store base register.  */
+             assert (GET_CODE (src) == PLUS);
+             assert (XEXP (src, 1) == stack_pointer_rtx);
+             assert (GET_CODE (XEXP (src, 0)) == REG
+                     && REGNO (XEXP (src, 0)) == cfa_temp_reg);
+             assert (cfa_store_reg == STACK_POINTER_REGNUM);
+             cfa_store_reg = REGNO (dest);
+             cfa_store_offset -= cfa_temp_value;
+           }
+         break;
+
+       case CONST_INT:
+         cfa_temp_reg = REGNO (dest);
+         cfa_temp_value = INTVAL (src);
+         break;
+
+       default:
+         abort ();
+       }
+      dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
+      break;
+
+    case MEM:
+      /* Saving a register to the stack.  Make sure dest is relative to the
+         CFA register.  */
+      assert (GET_CODE (src) == REG);
+      switch (GET_CODE (XEXP (dest, 0)))
+       {
+         /* With a push.  */
+       case PRE_INC:
+       case PRE_DEC:
+         offset = GET_MODE_SIZE (GET_MODE (dest));
+         if (GET_CODE (src) == PRE_INC)
+           offset = -offset;
+
+         assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM);
+         assert (cfa_store_reg == STACK_POINTER_REGNUM);
+         cfa_store_offset += offset;
+         if (cfa_reg == STACK_POINTER_REGNUM)
+           cfa_offset = cfa_store_offset;
+
+         offset = -cfa_store_offset;
+         break;
+
+         /* With an offset.  */
+       case PLUS:
+       case MINUS:
+         offset = INTVAL (XEXP (XEXP (dest, 0), 1));
+         if (GET_CODE (src) == MINUS)
+           offset = -offset;
+
+         assert (cfa_store_reg == REGNO (XEXP (XEXP (dest, 0), 0)));
+         offset -= cfa_store_offset;
+         break;
+
+       default:
+         abort ();
+       }
+      dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
+      dwarf2out_reg_save (label, REGNO (src), offset);
+      break;
+
+    default:
+      abort ();
     }
-  fputc ('\n', asm_out_file);
 }
 
 /* Return the size of a Call Frame Instruction.  */
+
 static unsigned long
 size_of_cfi (cfi)
      dw_cfi_ref cfi;
 {
   register unsigned long size;
-  /* count the 1-byte opcode */
+
+  /* Count the 1-byte opcode */
   size = 1;
   switch (cfi->dw_cfi_opc)
     {
     case DW_CFA_offset:
-      size += size_of_uleb128(cfi->dw_cfi_oprnd2.dw_cfi_offset);
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
       break;
     case DW_CFA_set_loc:
       size += PTR_SIZE;
@@ -3455,32 +4412,34 @@ size_of_cfi (cfi)
 #endif
     case DW_CFA_offset_extended:
     case DW_CFA_def_cfa:
-      size += size_of_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-      size += size_of_uleb128(cfi->dw_cfi_oprnd2.dw_cfi_offset);
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
       break;
     case DW_CFA_restore_extended:
     case DW_CFA_undefined:
-      size += size_of_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
       break;
     case DW_CFA_same_value:
     case DW_CFA_def_cfa_register:
-      size += size_of_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
       break;
     case DW_CFA_register:
-      size += size_of_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-      size += size_of_uleb128(cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
       break;
     case DW_CFA_def_cfa_offset:
-      size += size_of_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_offset);
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
       break;
     default:
       break;
     }
+
     return size;
 }
 
 /* Return the size of an FDE sans the length word.  */
-inline unsigned long
+
+static inline unsigned long
 size_of_fde (fde, npad)
     dw_fde_ref fde;
     unsigned long *npad;
@@ -3488,26 +4447,36 @@ size_of_fde (fde, npad)
   register dw_cfi_ref cfi;
   register unsigned long aligned_size;
   register unsigned long size;
+
   size = DWARF_FDE_HEADER_SIZE;
   for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-    {
-       size += size_of_cfi(cfi);
-    }
-  /* Round the size up to an 8 byte boundary.  */
-  aligned_size = (size + 7) & ~7;
+    size += size_of_cfi(cfi);
+
+  /* Round the size up to a word boundary.  */
+  aligned_size = DWARF_ROUND (size, PTR_SIZE);
   *npad = aligned_size - size;
   return aligned_size;
 }
 
 /* Calculate the size of the FDE table, and establish the offset
    of each FDE in the .debug_frame section.  */
+
 static void
 calc_fde_sizes ()
 {
   register unsigned long i;
   register dw_fde_ref fde;
   register unsigned long fde_size;
+  register dw_cfi_ref cfi;
   unsigned long fde_pad;
+
+  cie_size = DWARF_CIE_HEADER_SIZE;
+  for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
+    cie_size += size_of_cfi (cfi);
+
+  /* Initialize the beginning FDE offset.  */
+  next_fde_offset = DWARF_ROUND (cie_size, PTR_SIZE);
+
   for (i = 0; i < fde_table_in_use; ++i)
     {
       fde = &fde_table[i];
@@ -3518,6 +4487,7 @@ calc_fde_sizes ()
 }
 
 /* Output a Call Frame Information opcode and its operand(s).  */
+
 static void
 output_cfi (cfi, fde)
      register dw_cfi_ref cfi;
@@ -3529,22 +4499,22 @@ output_cfi (cfi, fde)
                              cfi->dw_cfi_opc
                              | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f));
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s DW_CFA_advance_loc", ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%x",
+                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
       fputc ('\n', asm_out_file);
     }
+
   else if (cfi->dw_cfi_opc == DW_CFA_offset)
     {
       ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
                              cfi->dw_cfi_opc
                              | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s DW_CFA_offset", ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%x",
+                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+
       fputc ('\n', asm_out_file);
-      output_uleb128(cfi->dw_cfi_oprnd2.dw_cfi_offset);
+      output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
       fputc ('\n', asm_out_file);
     }
   else if (cfi->dw_cfi_opc == DW_CFA_restore)
@@ -3553,26 +4523,23 @@ output_cfi (cfi, fde)
                              cfi->dw_cfi_opc
                              | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s DW_CFA_restore", ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%x",
+                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+
       fputc ('\n', asm_out_file);
     }
   else
     {
       ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s %s",
-                  ASM_COMMENT_START,
-                  dwarf_cfi_name (cfi->dw_cfi_opc));
-       }
+       fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
+                dwarf_cfi_name (cfi->dw_cfi_opc));
+
       fputc ('\n', asm_out_file);
       switch (cfi->dw_cfi_opc)
        {
        case DW_CFA_set_loc:
-          ASM_OUTPUT_DWARF_ADDR (asm_out_file,
-                                cfi->dw_cfi_oprnd1.dw_cfi_addr);
+          ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr);
           fputc ('\n', asm_out_file);
          break;
        case DW_CFA_advance_loc1:
@@ -3581,15 +4548,17 @@ output_cfi (cfi, fde)
          break;
        case DW_CFA_advance_loc2:
           ASM_OUTPUT_DWARF_DELTA2 (asm_out_file,
-                                cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                                fde->dw_fde_begin);
+                                  cfi->dw_cfi_oprnd1.dw_cfi_addr,
+                                  fde->dw_fde_current_label);
           fputc ('\n', asm_out_file);
+         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
          break;
        case DW_CFA_advance_loc4:
           ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
-                                cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                                fde->dw_fde_begin);
+                                  cfi->dw_cfi_oprnd1.dw_cfi_addr,
+                                  fde->dw_fde_current_label);
           fputc ('\n', asm_out_file);
+         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
          break;
 #ifdef MIPS_DEBUGGING_INFO
        case DW_CFA_MIPS_advance_loc8:
@@ -3599,29 +4568,29 @@ output_cfi (cfi, fde)
 #endif
        case DW_CFA_offset_extended:
        case DW_CFA_def_cfa:
-         output_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
           fputc ('\n', asm_out_file);
-         output_uleb128(cfi->dw_cfi_oprnd2.dw_cfi_offset);
+         output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
           fputc ('\n', asm_out_file);
          break;
        case DW_CFA_restore_extended:
        case DW_CFA_undefined:
-         output_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
           fputc ('\n', asm_out_file);
          break;
        case DW_CFA_same_value:
        case DW_CFA_def_cfa_register:
-         output_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
           fputc ('\n', asm_out_file);
          break;
        case DW_CFA_register:
-         output_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
           fputc ('\n', asm_out_file);
-         output_uleb128(cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
+         output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
           fputc ('\n', asm_out_file);
          break;
        case DW_CFA_def_cfa_offset:
-         output_uleb128(cfi->dw_cfi_oprnd1.dw_cfi_offset);
+         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
           fputc ('\n', asm_out_file);
          break;
        default:
@@ -3633,91 +4602,84 @@ output_cfi (cfi, fde)
 /* Output the call frame information used to used to record information
    that relates to calculating the frame pointer, and records the
    location of saved registers.  */
+
 static void
 output_call_frame_info ()
 {
   register unsigned long i, j;
   register dw_fde_ref fde;
   register unsigned long fde_size;
-  dw_cfi_node cfi_node;
   register dw_cfi_ref cfi;
   unsigned long fde_pad;
 
+  /* Only output the info if it will be interesting.  */
+  for (i = 0; i < fde_table_in_use; ++i)
+    if (fde_table[i].dw_fde_cfi != NULL)
+      break;
+  if (i == fde_table_in_use)
+    return;
+
+  /* (re-)initialize the beginning FDE offset.  */
+  next_fde_offset = DWARF_ROUND (cie_size, PTR_SIZE);
+
+  fputc ('\n', asm_out_file);
+  ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
+
   /* Output the CIE. */
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DWARF_CIE_SIZE - 4);
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, next_fde_offset - DWARF_OFFSET_SIZE);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Length of Common Information Entry",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Length of Common Information Entry",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
   if (flag_verbose_asm)
+    fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
+
+  fputc ('\n', asm_out_file);
+  if (DWARF_OFFSET_SIZE == 8)
     {
-      fprintf (asm_out_file, "\t%s CIE Identifier Tag",
-              ASM_COMMENT_START);
+      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
+      fputc ('\n', asm_out_file);
     }
-  fputc ('\n', asm_out_file);
+
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s CIE Version",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s CIE Augmentation (none)", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   output_uleb128 (1);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s CIE Code Alignment Factor",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, " (CIE Code Alignment Factor)");
+
   fputc ('\n', asm_out_file);
   output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s CIE Data Alignment Factor",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, " (CIE Data Alignment Factor)");
+
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_FRAME_RA_COL);
+  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s CIE RA Column",
-              ASM_COMMENT_START);
-    }
-  fputc ('\n', asm_out_file);
-
-  /* Output the CFA instructions common to all FDE's. */
-
-#ifdef MIPS_DEBUGGING_INFO
+    fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
 
-  /* Set the RA on entry to be the contents of r31.  */
-  bzero (&cfi_node, sizeof (dw_cfi_node));
-  cfi = &cfi_node;
-  cfi->dw_cfi_opc = DW_CFA_register;
-  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DW_FRAME_RA_COL;
-  cfi->dw_cfi_oprnd2.dw_cfi_reg_num = DW_FRAME_REG31;
-  output_cfi (cfi);
+  fputc ('\n', asm_out_file);
 
-#endif
+  for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
+    output_cfi (cfi, NULL);
 
   /* Pad the CIE out to an address sized boundary.  */
-  for (i = DWARF_CIE_HEADER_SIZE; i < DWARF_CIE_SIZE; ++i)
+  for (i = next_fde_offset - cie_size; i; --i)
     {
       /* Pad out to a pointer size boundary */
       ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CFA_nop);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s CIE DW_CFA_nop (pad)",
-                  ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s CIE DW_CFA_nop (pad)", ASM_COMMENT_START);
+
       fputc ('\n', asm_out_file);
     }
 
@@ -3725,266 +4687,322 @@ output_call_frame_info ()
   for (i = 0; i < fde_table_in_use; ++i)
     {
       fde = &fde_table[i];
+      if (fde->dw_fde_cfi == NULL)
+       continue;
+
       fde_size = size_of_fde (fde, &fde_pad);
-      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, fde_size - 4);
+      ASM_OUTPUT_DWARF_DATA (asm_out_file, fde_size - DWARF_OFFSET_SIZE);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s FDE Length",
-                  ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
+
       fputc ('\n', asm_out_file);
-      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
+      ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION));
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s FDE CIE offset",
-                  ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
+
       fputc ('\n', asm_out_file);
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s FDE initial location",
-                  ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START);
+
       fputc ('\n', asm_out_file);
-      ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
-                              fde->dw_fde_end, fde->dw_fde_begin);
+      ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
+                                  fde->dw_fde_end, fde->dw_fde_begin);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s FDE address range",
-                  ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
+
       fputc ('\n', asm_out_file);
 
       /* Loop through the Call Frame Instructions associated with
         this FDE.  */
+      fde->dw_fde_current_label = fde->dw_fde_begin;
       for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-       {
-         output_cfi (cfi, fde);
-       }
+       output_cfi (cfi, fde);
 
       /* Pad to a double word boundary.  */
       for (j = 0; j < fde_pad; ++j)
        {
          ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CFA_nop);
          if (flag_verbose_asm)
-           {
-             fprintf (asm_out_file, "\t%s CIE DW_CFA_nop (pad)",
-                      ASM_COMMENT_START);
-           }
+           fprintf (asm_out_file, "\t%s CIE DW_CFA_nop (pad)",
+                    ASM_COMMENT_START);
+
          fputc ('\n', asm_out_file);
        }
     }
 }
 
+/* The DWARF2 pubname for a nested thingy looks like "A::f".  The output
+   of decl_printable_name for C++ looks like "A::f(int)".  Let's drop the
+   argument list, and maybe the scope.  */
+
+static char *
+dwarf2_name (decl, scope)
+     tree decl;
+     int scope;
+{
+  return (*decl_printable_name) (decl, scope ? 1 : 0);
+}
+
+/* Add a new entry to .debug_pubnames if appropriate.  */
+
+static void
+add_pubname (decl, die)
+     tree decl;
+     dw_die_ref die;
+{
+  pubname_ref p;
+
+  if (! TREE_PUBLIC (decl))
+    return;
+
+  if (pubname_table_in_use == pubname_table_allocated)
+    {
+      pubname_table_allocated += PUBNAME_TABLE_INCREMENT;
+      pubname_table = (pubname_ref) xrealloc
+       (pubname_table, pubname_table_allocated * sizeof (pubname_entry));
+    }
+
+  p = &pubname_table[pubname_table_in_use++];
+  p->die = die;
+
+  p->name = xstrdup (dwarf2_name (decl, 1));
+}
+
 /* Output the public names table used to speed up access to externally
    visible names.  For now, only generate entries for externally
    visible procedures.  */
+
 static void
 output_pubnames ()
 {
-  dw_die_ref die;
+  register unsigned i;
   register unsigned long pubnames_length = size_of_pubnames ();
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, pubnames_length);
+
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length);
+
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Length of Public Names Info.",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Length of Public Names Info.",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
+
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s DWARF Version",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_ADDR (asm_out_file, stripattributes (DEBUG_SECTION));
+  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_SECTION));
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, next_die_offset);
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset);
   if (flag_verbose_asm)
+    fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START);
+
+  fputc ('\n', asm_out_file);
+  for (i = 0; i < pubname_table_in_use; ++i)
     {
-      fprintf (asm_out_file, "\t%s Compilation Unit Length",
-              ASM_COMMENT_START);
+      register pubname_ref pub = &pubname_table[i];
+
+      ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset);
+      if (flag_verbose_asm)
+       fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START);
+
+      fputc ('\n', asm_out_file);
+
+      ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name);
+      if (flag_verbose_asm)
+       fprintf (asm_out_file, "%s external name", ASM_COMMENT_START);
+
+      fputc ('\n', asm_out_file);
     }
+
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, 0);
   fputc ('\n', asm_out_file);
-  for (die = comp_unit_die->die_child; die != NULL; die = die->die_sib)
+}
+
+/* Add a new entry to .debug_aranges if appropriate.  */
+
+static void
+add_arange (decl, die)
+     tree decl;
+     dw_die_ref die;
+{
+  if (! DECL_SECTION_NAME (decl))
+    return;
+
+  if (arange_table_in_use == arange_table_allocated)
     {
-      if (is_extern_subr_die (die))
-       {
-         char *low_pc = get_AT_low_pc (die);
-         if (low_pc != NULL)
-           {
-             ASM_OUTPUT_DWARF_DATA4 (asm_out_file, die->die_offset);
-             if (flag_verbose_asm)
-               {
-                 fprintf (asm_out_file, "\t%s DIE offset",
-                          ASM_COMMENT_START);
-               }
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_STRING (asm_out_file, low_pc);
-             if (flag_verbose_asm)
-               {
-                 fprintf (asm_out_file, "%s external name",
-                          ASM_COMMENT_START);
-               }
-             fputc ('\n', asm_out_file);
-           }
-       }
+      arange_table_allocated += ARANGE_TABLE_INCREMENT;
+      arange_table
+       = (arange_ref) xrealloc (arange_table,
+                                arange_table_allocated * sizeof (dw_die_ref));
     }
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
-  fputc ('\n', asm_out_file);
+
+  arange_table[arange_table_in_use++] = die;
 }
 
 /* Output the information that goes into the .debug_aranges table.
    Namely, define the beginning and ending address range of the
    text section generated for this compilation unit.  */
+
 static void
 output_aranges ()
 {
-  dw_die_ref die;
+  register unsigned i;
   register unsigned long aranges_length = size_of_aranges ();
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, aranges_length);
+
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Length of Address Ranges Info.",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Length of Address Ranges Info.",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s DWARF Version",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_ADDR (asm_out_file, stripattributes (DEBUG_SECTION));
+  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_SECTION));
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Size of Address",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Size of Segment Descriptor",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Size of Segment Descriptor",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4);
+  if (PTR_SIZE == 8)
+    fprintf (asm_out_file, ",0,0");
+
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Pad to 8 byte boundary",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Pad to %d byte boundary",
+            ASM_COMMENT_START, 2 * PTR_SIZE);
+
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
+  ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, TEXT_END_LABEL, TEXT_BEGIN_LABEL);
+  ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label, TEXT_SECTION);
   if (flag_verbose_asm)
+    fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
+
+  fputc ('\n', asm_out_file);
+  for (i = 0; i < arange_table_in_use; ++i)
     {
-      fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
+      dw_die_ref a = arange_table[i];
+
+      if (a->die_tag == DW_TAG_subprogram)
+       ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (a));
+      else
+       {
+         char *name = get_AT_string (a, DW_AT_MIPS_linkage_name);
+         if (! name)
+           name = get_AT_string (a, DW_AT_name);
+
+         ASM_OUTPUT_DWARF_ADDR (asm_out_file, name);
+       }
+
+      if (flag_verbose_asm)
+       fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
+
+      fputc ('\n', asm_out_file);
+      if (a->die_tag == DW_TAG_subprogram)
+       ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (a),
+                                    get_AT_low_pc (a));
+      else
+       ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file,
+                                   get_AT_unsigned (a, DW_AT_byte_size));
+
+      if (flag_verbose_asm)
+       fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
+
+      fputc ('\n', asm_out_file);
     }
-  fputc ('\n', asm_out_file);
+
   /* Output the terminator words.  */
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
+  ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
+  ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
   fputc ('\n', asm_out_file);
 }
 
 /* Output the source line number correspondence information.  This
    information goes into the .debug_line section.  */
+
 static void
 output_line_info ()
 {
-  register unsigned long line_info_len;
-  register unsigned long line_info_prolog_len;
   char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
   char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
   register unsigned opc;
   register unsigned n_op_args;
-  register dw_line_info_ref line_info;
   register unsigned long ft_index;
   register unsigned long lt_index;
   register unsigned long current_line;
   register long line_offset;
   register long line_delta;
   register unsigned long current_file;
-  line_info_len = size_of_line_info ();
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, line_info_len);
+  register unsigned long function;
+
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_info ());
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Length of Source Line Info.",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Length of Source Line Info.",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s DWARF Version",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
-  line_info_prolog_len = size_of_line_prolog ();
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, line_info_prolog_len);
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ());
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Prolog Length",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Minimum Instruction Length",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Minimum Instruction Length",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Default is_stmt_start flag",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Default is_stmt_start flag",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)",
+            ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s Special Opcode Base",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; ++opc)
     {
@@ -4003,43 +5021,42 @@ output_line_info ()
        }
       ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args",
-                  ASM_COMMENT_START, opc, n_op_args);
-       }
+       fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args",
+                ASM_COMMENT_START, opc, n_op_args);
       fputc ('\n', asm_out_file);
     }
+
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "%s Include Directory Table\n",
-              ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START);
+
   /* Include directory table is empty, at present */
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
   fputc ('\n', asm_out_file);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START);
+
   for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
     {
       ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "%s File Entry: 0x%x",
-                  ASM_COMMENT_START, ft_index);
-       }
+       fprintf (asm_out_file, "%s File Entry: 0x%x",
+                ASM_COMMENT_START, ft_index);
+
       fputc ('\n', asm_out_file);
+
       /* Include directory index */
       output_uleb128 (0);
       fputc ('\n', asm_out_file);
+
       /* Modification time */
       output_uleb128 (0);
       fputc ('\n', asm_out_file);
+
       /* File length in bytes */
       output_uleb128 (0);
       fputc ('\n', asm_out_file);
     }
+
   /* Terminate the file name table */
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
   fputc ('\n', asm_out_file);
@@ -4047,32 +5064,32 @@ output_line_info ()
   /* Set the address register to the first location in the text section */
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
   if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
-    }
+    fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
+
   fputc ('\n', asm_out_file);
   output_uleb128 (1 + PTR_SIZE);
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
+  ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION);
   fputc ('\n', asm_out_file);
 
   /* Generate the line number to PC correspondence table, encoded as
      a series of state machine operations.  */
   current_file = 1;
   current_line = 1;
-  strcpy (prev_line_label, TEXT_BEGIN_LABEL);
+  strcpy (prev_line_label, TEXT_SECTION);
   for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
     {
+      register dw_line_info_ref line_info;
+
       ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
       if (flag_verbose_asm)
-       {
-         fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
-                  ASM_COMMENT_START);
-       }
+       fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
+                ASM_COMMENT_START);
+
       fputc ('\n', asm_out_file);
-      sprintf (line_label, LINE_CODE_LABEL_FMT, lt_index);
+      ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
       ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label);
       fputc ('\n', asm_out_file);
       line_info = &line_info_table[lt_index];
@@ -4081,19 +5098,120 @@ output_line_info ()
          current_file = line_info->dw_file_num;
          ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
          if (flag_verbose_asm)
-           {
+           fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
+
+         fputc ('\n', asm_out_file);
+         output_uleb128 (current_file);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
+
+         fputc ('\n', asm_out_file);
+       }
+
+      line_offset = line_info->dw_line_num - current_line;
+      line_delta = line_offset - DWARF_LINE_BASE;
+      current_line = line_info->dw_line_num;
+      if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+       {
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+                                 DWARF_LINE_OPCODE_BASE + line_delta);
+         if (flag_verbose_asm)
              fprintf (asm_out_file,
-                      "\t%s DW_LNS_set_file", ASM_COMMENT_START);
-           }
+                      "\t%s line %d", ASM_COMMENT_START, current_line);
+
+         fputc ('\n', asm_out_file);
+       }
+      else
+       {
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s advance to line %d",
+                    ASM_COMMENT_START, current_line);
+
+         fputc ('\n', asm_out_file);
+         output_sleb128 (line_offset);
+         fputc ('\n', asm_out_file);
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
+         fputc ('\n', asm_out_file);
+       }
+
+      strcpy (prev_line_label, line_label);
+    }
+
+  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
+  if (flag_verbose_asm)
+    fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", ASM_COMMENT_START);
+
+  fputc ('\n', asm_out_file);
+  ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label);
+  fputc ('\n', asm_out_file);
+
+  /* Output the marker for the end of the line number info.  */
+  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+  if (flag_verbose_asm)
+    fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START);
+
+  fputc ('\n', asm_out_file);
+  output_uleb128 (1);
+  fputc ('\n', asm_out_file);
+  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
+  fputc ('\n', asm_out_file);
+
+  function = 0;
+  current_file = 1;
+  current_line = 1;
+  for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
+    {
+      register dw_separate_line_info_ref line_info
+       = &separate_line_info_table[lt_index];
+
+      ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
+                                  lt_index);
+      if (function != line_info->function)
+       {
+         function = line_info->function;
+
+         /* Set the address register to the first line in the function */
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s DW_LNE_set_address",
+                    ASM_COMMENT_START);
+
+         fputc ('\n', asm_out_file);
+         output_uleb128 (1 + PTR_SIZE);
+         fputc ('\n', asm_out_file);
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
+         fputc ('\n', asm_out_file);
+         ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
+         fputc ('\n', asm_out_file);
+       }
+      else
+       {
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
+                    ASM_COMMENT_START);
+
+         fputc ('\n', asm_out_file);
+         ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label);
+         fputc ('\n', asm_out_file);
+       }
+
+      if (line_info->dw_file_num != current_file)
+       {
+         current_file = line_info->dw_file_num;
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
+
          fputc ('\n', asm_out_file);
          output_uleb128 (current_file);
          if (flag_verbose_asm)
-           {
-             fprintf (asm_out_file, "\t%s \"%s\"",
-                      ASM_COMMENT_START, file_table[current_file]);
-           }
+           fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
+
          fputc ('\n', asm_out_file);
        }
+
       if (line_info->dw_line_num != current_line)
        {
          line_offset = line_info->dw_line_num - current_line;
@@ -4104,21 +5222,18 @@ output_line_info ()
              ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
                                      DWARF_LINE_OPCODE_BASE + line_delta);
              if (flag_verbose_asm)
-               {
-                 fprintf (asm_out_file,
-                          "\t%s line %d", ASM_COMMENT_START, current_line);
-               }
+               fprintf (asm_out_file,
+                        "\t%s line %d", ASM_COMMENT_START, current_line);
+
              fputc ('\n', asm_out_file);
            }
          else
            {
              ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
              if (flag_verbose_asm)
-               {
-                 fprintf (asm_out_file,
-                          "\t%s advance to line %d",
-                          ASM_COMMENT_START, current_line);
-               }
+               fprintf (asm_out_file, "\t%s advance to line %d",
+                        ASM_COMMENT_START, current_line);
+
              fputc ('\n', asm_out_file);
              output_sleb128 (line_offset);
              fputc ('\n', asm_out_file);
@@ -4126,48 +5241,52 @@ output_line_info ()
              fputc ('\n', asm_out_file);
            }
        }
+
+      ++lt_index;
       strcpy (prev_line_label, line_label);
-    }
 
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-  if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
-    }
-  fputc ('\n', asm_out_file);
-  output_uleb128 (1 + PTR_SIZE);
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_END_LABEL);
-  fputc ('\n', asm_out_file);
-  /* Output the marker for the end of the line number info.  */
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-  if (flag_verbose_asm)
-    {
-      fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START);
+      /* If we're done with a function, end its sequence.  */
+      if (lt_index == separate_line_info_table_in_use
+         || separate_line_info_table[lt_index].function != function)
+       {
+         current_file = 1;
+         current_line = 1;
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
+                    ASM_COMMENT_START);
+
+         fputc ('\n', asm_out_file);
+         ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
+         ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label);
+         fputc ('\n', asm_out_file);
+
+         /* Output the marker for the end of this sequence.  */
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+         if (flag_verbose_asm)
+           fprintf (asm_out_file, "\t%s DW_LNE_end_sequence",
+                    ASM_COMMENT_START);
+
+         fputc ('\n', asm_out_file);
+         output_uleb128 (1);
+         fputc ('\n', asm_out_file);
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
+         fputc ('\n', asm_out_file);
+       }
     }
-  fputc ('\n', asm_out_file);
-  output_uleb128 (1);
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
-  fputc ('\n', asm_out_file);
 }
 \f
-/**************** attribute support utilities ********************************/
-
-/*
- * Given a pointer to a BLOCK node return non-zero if (and only if) the node
- * in question represents the outermost pair of curly braces (i.e. the "body
- * block") of a function or method.
- *
- * For any BLOCK node representing a "body block" of a function or method, the
- * BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which
- * represents the outermost (function) scope for the function or method (i.e.
- * the one which includes the formal parameters).  The BLOCK_SUPERCONTEXT of
- * *that* node in turn will point to the relevant FUNCTION_DECL node.
- */
-inline int
+/* Given a pointer to a BLOCK node return non-zero if (and only if) the node
+   in question represents the outermost pair of curly braces (i.e. the "body
+   block") of a function or method.
+
+   For any BLOCK node representing a "body block" of a function or method, the
+   BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which
+   represents the outermost (function) scope for the function or method (i.e.
+   the one which includes the formal parameters).  The BLOCK_SUPERCONTEXT of
+   *that* node in turn will point to the relevant FUNCTION_DECL node. */
+
+static inline int
 is_body_block (stmt)
      register tree stmt;
 {
@@ -4183,38 +5302,8 @@ is_body_block (stmt)
            return 1;
        }
     }
-  return 0;
-}
 
-/* Reset the base type to DIE table, and build a special predefined
-   base type entry for the "int" signed integer base type.  The
-   "int" base type is used to construct subscript index range
-   definitions, in situations where an anonymous integer type
-   is required.  */
-inline void
-init_base_type_table ()
-{
-  register int i;
-  register base_type_ref bt;
-  for (i = 0; i < NUM_BASE_TYPES; ++i)
-    {
-      base_type_die_table[i] = NULL;
-    }
-  assert (comp_unit_die != 0);
-  for (i = 0; i < NUM_BASE_TYPES; ++i)
-    {
-      bt = &base_type_table[i];
-      if (strcmp (bt->bt_name, "int") == 0)
-       {
-         int_base_type_die = new_die (DW_TAG_base_type, comp_unit_die);
-         base_type_die_table[i] = int_base_type_die;
-         add_AT_string (int_base_type_die, DW_AT_name, bt->bt_name);
-         add_AT_unsigned (int_base_type_die,
-                          DW_AT_byte_size, bt->bt_size / 8);
-         add_AT_unsigned (int_base_type_die, DW_AT_encoding, bt->bt_type);
-         break;
-       }
-    }
+  return 0;
 }
 
 /* Given a pointer to a tree node for some base type, return a pointer to
@@ -4222,148 +5311,74 @@ init_base_type_table ()
 
    This routine must only be called for GCC type nodes that correspond to
    Dwarf base (fundamental) types.  */
+
 static dw_die_ref
 base_type_die (type)
      register tree type;
 {
-  register dw_die_ref base_type_result = NULL;
-  register char *type_name = NULL;
-  register int type_index = 0;
-  register base_type_ref bt;
-  register int i;
+  register dw_die_ref base_type_result;
+  register char *type_name;
+  register enum dwarf_type encoding;
+  register tree name = TYPE_NAME (type);
 
-  if (TREE_CODE (type) == ERROR_MARK)
+  if (TREE_CODE (type) == ERROR_MARK
+      || TREE_CODE (type) == VOID_TYPE)
     return 0;
 
+  if (TREE_CODE (name) == TYPE_DECL)
+    name = DECL_NAME (name);
+  type_name = IDENTIFIER_POINTER (name);
+
   switch (TREE_CODE (type))
     {
-    case VOID_TYPE:
-    case ERROR_MARK:
-      break;
-
     case INTEGER_TYPE:
-      /* Carefully distinguish all the standard types of C, without messing
+      /* Carefully distinguish the C character types, without messing
          up if the language is not C. Note that we check only for the names
          that contain spaces; other names might occur by coincidence in other 
          languages.  */
-      if (TYPE_NAME (type) != 0
-         && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
-         && DECL_NAME (TYPE_NAME (type)) != 0
-         && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE)
+      if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
+            && (type == char_type_node
+                || ! strcmp (type_name, "signed char")
+                || ! strcmp (type_name, "unsigned char"))))
        {
-         type_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
-         for (i = 0; i < NUM_BASE_TYPES; ++i)
-           {
-             bt = &base_type_table[i];
-             if (strcmp (type_name, bt->bt_name) == 0)
-               {
-                 type_index = i;
-                 break;
-               }
-           }
+         if (TREE_UNSIGNED (type))
+           encoding = DW_ATE_unsigned;
+         else
+           encoding = DW_ATE_signed;
+         break;
        }
+      /* else fall through */
 
-      /* Most integer types will be sorted out above, however, for the sake
-         of special `array index' integer types, the following code is also
-         provided.  */
-      if (type_index == 0)
-       {
-         for (i = 0; i < NUM_BASE_TYPES; ++i)
-           {
-             bt = &base_type_table[i];
-             if (bt->bt_size == TYPE_PRECISION (type)
-                 && (TREE_UNSIGNED (type) == 0) == bt->bt_is_signed)
-               {
-                 type_index = i;
-                 break;
-               }
-           }
-       }
+    case CHAR_TYPE:
+      /* GNU Pascal/Ada CHAR type.  Not used in C.  */
+      if (TREE_UNSIGNED (type))
+       encoding = DW_ATE_unsigned_char;
+      else
+       encoding = DW_ATE_signed_char;
       break;
 
     case REAL_TYPE:
-      /* Carefully distinguish all the standard types of C, without messing
-         up if the language is not C.  */
-      for (i = 0; i < NUM_BASE_TYPES; ++i)
-       {
-         bt = &base_type_table[i];
-         if ((bt->bt_type == DW_ATE_float)
-             && (bt->bt_size == TYPE_PRECISION (type)))
-           {
-             type_index = i;
-             break;
-           }
-       }
+      encoding = DW_ATE_float;
       break;
 
     case COMPLEX_TYPE:
-      for (i = 0; i < NUM_BASE_TYPES; ++i)
-       {
-         bt = &base_type_table[i];
-         if ((bt->bt_type == DW_ATE_complex_float)
-             && (bt->bt_size == TYPE_PRECISION (type)))
-           {
-             type_index = i;
-             break;
-           }
-       }
-      break;
-
-    case CHAR_TYPE:
-      /* GNU Pascal/Ada CHAR type.  Not used in C.  */
-      for (i = 0; i < NUM_BASE_TYPES; ++i)
-       {
-         bt = &base_type_table[i];
-         if (bt->bt_type == DW_ATE_signed_char
-             || bt->bt_type == DW_ATE_unsigned_char)
-           {
-             if (bt->bt_size == TYPE_PRECISION (type)
-                 && ((TREE_UNSIGNED (type) == 0) == bt->bt_is_signed))
-               {
-                 type_index = i;
-                 break;
-               }
-           }
-       }
+      encoding = DW_ATE_complex_float;
       break;
 
     case BOOLEAN_TYPE:
-      /* GNU FORTRAN/Ada BOOLEAN type.  */
-      for (i = 0; i < NUM_BASE_TYPES; ++i)
-       {
-         bt = &base_type_table[i];
-         if (bt->bt_type == DW_ATE_boolean
-             && bt->bt_size == TYPE_PRECISION (type))
-           {
-             type_index = i;
-             break;
-           }
-       }
+      /* GNU FORTRAN/Ada/C++ BOOLEAN type.  */
+      encoding = DW_ATE_boolean;
       break;
 
     default:
-      abort ();                        /* No other TREE_CODEs are Dwarf fundamental
-                                  types.  */
-    }
-
-  if (type_index == 0)
-    {
-      base_type_result = NULL;
+      abort (); /* No other TREE_CODEs are Dwarf fundamental types.  */
     }
-  else
-    {
-      base_type_result = base_type_die_table[type_index];
-      if (base_type_result == NULL)
-       {
-         bt = &base_type_table[type_index];
-         base_type_result = new_die (DW_TAG_base_type, comp_unit_die);
-         base_type_die_table[type_index] = base_type_result;
-         add_AT_string (base_type_result, DW_AT_name, bt->bt_name);
-         add_AT_unsigned (base_type_result, DW_AT_byte_size, bt->bt_size / 8);
-         add_AT_unsigned (base_type_result, DW_AT_encoding, bt->bt_type);
-       }
 
-    }
+  base_type_result = new_die (DW_TAG_base_type, comp_unit_die);
+  add_AT_string (base_type_result, DW_AT_name, type_name);
+  add_AT_unsigned (base_type_result, DW_AT_byte_size,
+                  TYPE_PRECISION (type) / BITS_PER_UNIT);
+  add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
 
   return base_type_result;
 }
@@ -4376,6 +5391,7 @@ base_type_die (type)
    type.  (This definition of the "root" type is recursive.) Also, the root
    type of a `const' qualified type or a `volatile' qualified type is the
    root type of the given type without the qualifiers.  */
+
 static tree
 root_type (type)
      register tree type;
@@ -4399,7 +5415,8 @@ root_type (type)
 
 /* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the
    given input type is a Dwarf "fundamental" type.  Otherwise return null.  */
-inline int
+
+static inline int
 is_base_type (type)
      register tree type;
 {
@@ -4432,11 +5449,13 @@ is_base_type (type)
     default:
       abort ();
     }
+
   return 0;
 }
 
 /* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
    entry that chains various modifiers in front of the given type.  */
+
 static dw_die_ref
 modified_type_die (type, is_const_type, is_volatile_type, context_die)
      register tree type;
@@ -4447,108 +5466,107 @@ modified_type_die (type, is_const_type, is_volatile_type, context_die)
   register enum tree_code code = TREE_CODE (type);
   register dw_die_ref mod_type_die = NULL;
   register dw_die_ref sub_die = NULL;
-  register tree item_type;
+  register tree item_type = NULL;
 
   if (code != ERROR_MARK)
     {
-      if (is_const_type)
+      type = build_type_variant (type, is_const_type, is_volatile_type);
+
+      mod_type_die = lookup_type_die (type);
+      if (mod_type_die)
+       return mod_type_die;
+
+      /* Handle C typedef types. */
+      if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+         && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+       {
+         tree dtype = TREE_TYPE (TYPE_NAME (type));
+         if (type == dtype)
+           {
+             /* For a named type, use the typedef.  */
+             gen_type_die (type, context_die);
+             mod_type_die = lookup_type_die (type);
+           }
+
+         else if (is_const_type < TYPE_READONLY (dtype)
+                  || is_volatile_type < TYPE_VOLATILE (dtype))
+           /* cv-unqualified version of named type.  Just use the unnamed
+              type to which it refers.  */
+           mod_type_die
+             = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)),
+                                  is_const_type, is_volatile_type,
+                                  context_die);
+         /* Else cv-qualified version of named type; fall through.  */
+       }
+
+      if (mod_type_die)
+       /* OK */;
+      else if (is_const_type)
        {
-         mod_type_die = new_die (DW_TAG_const_type, context_die);
-         sub_die = modified_type_die (type,
-                                      0, is_volatile_type, context_die);
+         mod_type_die = new_die (DW_TAG_const_type, comp_unit_die);
+         sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
        }
       else if (is_volatile_type)
        {
-         mod_type_die = new_die (DW_TAG_volatile_type, context_die);
+         mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die);
          sub_die = modified_type_die (type, 0, 0, context_die);
        }
       else if (code == POINTER_TYPE)
        {
-         mod_type_die = new_die (DW_TAG_pointer_type, context_die);
+         mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die);
          add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+#if 0
          add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
+#endif
          item_type = TREE_TYPE (type);
-         sub_die = modified_type_die (item_type,
-                                      TYPE_READONLY (item_type),
-                                      TYPE_VOLATILE (item_type),
-                                      context_die);
        }
       else if (code == REFERENCE_TYPE)
        {
-         mod_type_die = new_die (DW_TAG_reference_type, context_die);
+         mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die);
          add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+#if 0
          add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
+#endif 
          item_type = TREE_TYPE (type);
-         sub_die = modified_type_die (item_type,
-                                      TYPE_READONLY (item_type),
-                                      TYPE_VOLATILE (item_type),
-                                      context_die);
        }
       else if (is_base_type (type))
-       {
-         mod_type_die = base_type_die (type);
-       }
+       mod_type_die = base_type_die (type);
       else
        {
+         gen_type_die (type, context_die);
+
          /* We have to get the type_main_variant here (and pass that to the
             `lookup_type_die' routine) because the ..._TYPE node we have
             might simply be a *copy* of some original type node (where the
             copy was created to help us keep track of typedef names) and
             that copy might have a different TYPE_UID from the original
-            ..._TYPE node.  (Note that when `equate_type_number_to_die' is
-            labeling a given type DIE for future reference, it always only
-            handles DIEs representing *main variants*, and it never even
-            knows about non-main-variants.).  */
+            ..._TYPE node.  */
          mod_type_die = lookup_type_die (type_main_variant (type));
-
-         /* Normally, we assume that all types are defined before they are
-            referenced.  If this is not the case, then mod_type_die will
-            be NULL here, and we must backchain.  This can happen as the
-            result of a forward declaration of a structure tag.  */
-         if (mod_type_die == NULL)
-           {
-             dw_die_ref placeholder_die = new_die (DW_TAG_padding,
-                                                   context_die);
-             backchain_AT_die_ref (type, placeholder_die);
-           }
+         assert (mod_type_die != NULL);
        }
     }
-  if (sub_die != NULL)
-    {
-      add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
-    }
-  return mod_type_die;
-}
-
-/* Fix all unresolved die references that resulted from forward
-   declarations.  */
-static void
-resolve_backchains ()
-{
-  register backchain_ref back;
-
-  back = backchain;
-  while (back)
-    {
-      register dw_die_ref type_die;
 
-      type_die = lookup_type_die (type_main_variant (back->type));
+  equate_type_number_to_die (type, mod_type_die);
+  if (item_type)
+    /* We must do this after the equate_type_number_to_die call, in case
+       this is a recursive type.  This ensures that the modified_type_die
+       recursion will terminate even if the type is recursive.  Recursive
+       types are possible in Ada.  */
+    sub_die = modified_type_die (item_type,
+                                TYPE_READONLY (item_type),
+                                TYPE_VOLATILE (item_type),
+                                context_die);
 
-      assert (type_die != NULL);
-                                   
-      /* ??? It would be cleaner to find the die attribute, and change
-        the val_dir_ref field to point to this new die.  Just overwriting
-        the temporary die with the correct one is easier though, and seems
-        to work just as well.  */
-      memcpy (back->placeholder, type_die, sizeof (die_node));
+  if (sub_die != NULL)
+    add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
 
-      back = back->next;
-    }
+  return mod_type_die;
 }
 
 /* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
    an enumerated type.   */
-inline int
+
+static inline int
 type_is_enum (type)
      register tree type;
 {
@@ -4556,6 +5574,7 @@ type_is_enum (type)
 }
 
 /* Return the register number described by a given RTL node.  */
+
 static unsigned
 reg_number (rtl)
      register rtx rtl;
@@ -4568,72 +5587,74 @@ reg_number (rtl)
                         regno);
       regno = 0;
     }
+
   regno = DBX_REGISTER_NUMBER (regno);
   return regno;
 }
 
 /* Return a location descriptor that designates a machine register.  */
+
 static dw_loc_descr_ref
 reg_loc_descriptor (rtl)
      register rtx rtl;
 {
   register dw_loc_descr_ref loc_result = NULL;
   register unsigned reg = reg_number (rtl);
+
   if (reg >= 0 && reg <= 31)
-    {
-      loc_result = new_loc_descr (DW_OP_reg0 + reg, 0);
-    }
+    loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0);
   else
-    {
-      loc_result = new_loc_descr (DW_OP_regx, reg, 0);
-    }
+    loc_result = new_loc_descr (DW_OP_regx, reg, 0);
+
   return loc_result;
 }
 
 /* Return a location descriptor that designates a base+offset location.  */
+
 static dw_loc_descr_ref
 based_loc_descr (reg, offset)
      unsigned reg;
      long int offset;
 {
   register dw_loc_descr_ref loc_result;
-  register unsigned fp_reg = (frame_pointer_needed)
-                                     ? FRAME_POINTER_REGNUM
-                                     : STACK_POINTER_REGNUM;
+  /* For the "frame base", we use the frame pointer or stack pointer
+     registers, since the RTL for local variables is relative to one of
+     them.  */
+  register unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed
+                                                 ? HARD_FRAME_POINTER_REGNUM
+                                                 : STACK_POINTER_REGNUM);
+
   if (reg == fp_reg)
-    {
-      loc_result = new_loc_descr (DW_OP_fbreg,
-                                 offset - current_funcdef_frame_size, 0);
-    }
+    loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
   else if (reg >= 0 && reg <= 31)
-    {
-      loc_result = new_loc_descr (DW_OP_breg0 + reg, offset);
-    }
+    loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0);
   else
-    {
-      loc_result = new_loc_descr (DW_OP_bregx, reg, offset);
-    }
+    loc_result = new_loc_descr (DW_OP_bregx, reg, offset);
+
   return loc_result;
 }
 
 /* Return true if this RTL expression describes a base+offset calculation.  */
-inline int
+
+static inline int
 is_based_loc (rtl)
      register rtx rtl;
 {
-    return GET_CODE (rtl) == PLUS
-          && ((GET_CODE (XEXP (rtl, 0)) == REG
-               && GET_CODE (XEXP (rtl, 1)) == CONST_INT));
+    return (GET_CODE (rtl) == PLUS
+           && ((GET_CODE (XEXP (rtl, 0)) == REG
+                && GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
 }
 
 /* The following routine converts the RTL for a variable or parameter
    (resident in memory) into an equivalent Dwarf representation of a
    mechanism for getting the address of that same variable onto the top of a
    hypothetical "address evaluation" stack.
+
    When creating memory location descriptors, we are effectively transforming
    the RTL for a memory-resident object into its Dwarf postfix expression
    equivalent.  This routine recursively descends an RTL tree, turning
    it into Dwarf postfix code as it goes.  */
+
 static dw_loc_descr_ref
 mem_loc_descriptor (rtl)
      register rtx rtl;
@@ -4643,6 +5664,7 @@ mem_loc_descriptor (rtl)
      description of here will be the lowest numbered location which is
      actually within the array.  That's *not* necessarily the same as the
      zeroth element of the array.  */
+
   switch (GET_CODE (rtl))
     {
     case SUBREG:
@@ -4652,7 +5674,8 @@ mem_loc_descriptor (rtl)
          legitimate to make the Dwarf info refer to the whole register which
          contains the given subreg.  */
       rtl = XEXP (rtl, 0);
-      /* Drop thru.  */
+
+      /* ... fall through ... */
 
     case REG:
       /* Whenever a register number forms a part of the description of the
@@ -4685,11 +5708,8 @@ mem_loc_descriptor (rtl)
 
     case PLUS:
       if (is_based_loc (rtl))
-       {
-         mem_loc_result = based_loc_descr (
-                             reg_number (XEXP (rtl, 0)),
-                             INTVAL (XEXP (rtl, 1)));
-       }
+       mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)),
+                                         INTVAL (XEXP (rtl, 1)));
       else
        {
          add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0)));
@@ -4698,6 +5718,14 @@ mem_loc_descriptor (rtl)
        }
       break;
 
+    case MULT:
+      /* If a pseudo-reg is optimized away, it is possible for it to
+        be replaced with a MEM containing a multiply.  */
+      add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0)));
+      add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1)));
+      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+      break;
+
     case CONST_INT:
       mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0);
       break;
@@ -4705,6 +5733,7 @@ mem_loc_descriptor (rtl)
     default:
       abort ();
     }
+
   return mem_loc_result;
 }
 
@@ -4713,6 +5742,7 @@ mem_loc_descriptor (rtl)
    register, we just generate an OP_REG and the register number.  For a
    memory location we provide a Dwarf postfix expression describing how to
    generate the (dynamic) address of the object onto the address stack.  */
+
 static dw_loc_descr_ref
 loc_descriptor (rtl)
      register rtx rtl;
@@ -4721,19 +5751,17 @@ loc_descriptor (rtl)
   switch (GET_CODE (rtl))
     {
     case SUBREG:
-
       /* The case of a subreg may arise when we have a local (register)
          variable or a formal (register) parameter which doesn't quite fill
-         up an entire register.       For now, just assume that it is
+         up an entire register.  For now, just assume that it is
          legitimate to make the Dwarf info refer to the whole register which
          contains the given subreg.  */
-
       rtl = XEXP (rtl, 0);
-      loc_result = new_loc_descr (DW_OP_regx, reg_number (rtl), 0);
-      break;
+
+      /* ... fall through ... */
 
     case REG:
-      loc_result = new_loc_descr (DW_OP_regx, reg_number (rtl), 0);
+      loc_result = reg_loc_descriptor (rtl);
       break;
 
     case MEM:
@@ -4741,14 +5769,16 @@ loc_descriptor (rtl)
       break;
 
     default:
-      abort ();                        /* Should never happen */
+      abort ();
     }
+
   return loc_result;
 }
 
 /* Given an unsigned value, round it up to the lowest multiple of `boundary'
    which is not less than the value itself.  */
-inline unsigned
+
+static inline unsigned
 ceiling (value, boundary)
      register unsigned value;
      register unsigned boundary;
@@ -4760,7 +5790,8 @@ ceiling (value, boundary)
    pointer to the declared type for the relevant field variable, or return
    `integer_type_node' if the given node turns out to be an
    ERROR_MARK node.  */
-inline tree
+
+static inline tree
 field_type (decl)
      register tree decl;
 {
@@ -4770,7 +5801,7 @@ field_type (decl)
     return integer_type_node;
 
   type = DECL_BIT_FIELD_TYPE (decl);
-  if (type == NULL)
+  if (type == NULL_TREE)
     type = TREE_TYPE (decl);
 
   return type;
@@ -4780,7 +5811,8 @@ field_type (decl)
    node, return the alignment in bits for the type, or else return
    BITS_PER_WORD if the node actually turns out to be an
    ERROR_MARK node.  */
-inline unsigned
+
+static inline unsigned
 simple_type_align_in_bits (type)
      register tree type;
 {
@@ -4792,7 +5824,8 @@ simple_type_align_in_bits (type)
    return the alignment for the type if the type's size is not constant, or
    else return BITS_PER_WORD if the type actually turns out to be an
    ERROR_MARK node.  */
-inline unsigned
+
+static inline unsigned
 simple_type_size_in_bits (type)
      register tree type;
 {
@@ -4815,6 +5848,7 @@ simple_type_size_in_bits (type)
    determine what that offset is, either because the argument turns out to
    be a pointer to an ERROR_MARK node, or because the offset is actually
    variable.  (We can't handle the latter case just yet).  */
+
 static unsigned
 field_byte_offset (decl)
      register tree decl;
@@ -4852,10 +5886,9 @@ field_byte_offset (decl)
 
   if (TREE_CODE (field_size_tree) != INTEGER_CST)
     return 0;
-  field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree);
 
+  field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree);
   type_size_in_bits = simple_type_size_in_bits (type);
-
   type_align_in_bits = simple_type_align_in_bits (type);
   type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT;
 
@@ -4915,18 +5948,15 @@ field_byte_offset (decl)
 
   return object_offset_in_bytes;
 }
-
-
 \f
-/****************************** attributes *********************************/
-
-/* The following routines define various Dwarf attributes
-   (and any data associated with them).  */
+/* The following routines define various Dwarf attributes and any data
+   associated with them.  */
 
 
 /* Output the form of location attributes suitable for whole variables and
    whole parameters.  Note that the location attributes for struct fields are
    generated by the routine `data_member_location_attribute' below.  */
+
 static void
 add_location_attribute (die, rtl)
      dw_die_ref die;
@@ -4949,21 +5979,18 @@ add_location_attribute (die, rtl)
      certain kinds of DIEs is used to indicate something else entirely...
      i.e. that the DIE represents an object declaration, but not a
      definition.  So sayeth the PLSIG.  */
+
   if (!is_pseudo_reg (rtl)
       && (GET_CODE (rtl) != MEM
          || !is_pseudo_reg (XEXP (rtl, 0))))
-    {
-      loc_descr = loc_descriptor (eliminate_regs (rtl, 0, NULL_RTX));
-    }
+    loc_descr = loc_descriptor (eliminate_regs (rtl, 0, NULL_RTX, 0));
 
 #ifdef MIPS_DEBUGGING_INFO
   /* ??? SGI's dwarf reader is buggy, and will not accept a zero size
      location descriptor.  Lets just use r0 for now to represent a
      variable that has been optimized away.  */
   if (loc_descr == NULL)
-    {
-      loc_descr = loc_descriptor (gen_rtx (REG, word_mode, 0));
-    }
+    loc_descr = loc_descriptor (gen_rtx (REG, word_mode, 0));
 #endif
 
   add_AT_loc (die, DW_AT_location, loc_descr);
@@ -4987,18 +6014,25 @@ add_location_attribute (die, rtl)
    (See the `byte_size_attribute' function below.)  It is also used
    when calculating the value of the DW_AT_bit_offset attribute.
    (See the `bit_offset_attribute' function below).  */
+
 static void
 add_data_member_location_attribute (die, decl)
      register dw_die_ref die;
      register tree decl;
 {
-  register unsigned long offset = field_byte_offset (decl);
+  register unsigned long offset;
   register dw_loc_descr_ref loc_descr;
   register enum dwarf_location_atom op;
 
+  if (TREE_CODE (decl) == TREE_VEC)
+    offset = TREE_INT_CST_LOW (BINFO_OFFSET (decl));
+  else
+    offset = field_byte_offset (decl);
+
   /* The DWARF2 standard says that we should assume that the structure address
      is already on the stack, so we can specify a structure field address
      by using DW_OP_plus_uconst.  */
+
 #ifdef MIPS_DEBUGGING_INFO
   /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst operator
      correctly.  It works only if we leave the offset on the stack.  */
@@ -5006,6 +6040,7 @@ add_data_member_location_attribute (die, decl)
 #else
   op = DW_OP_plus_uconst;
 #endif
+
   loc_descr = new_loc_descr (op, offset, 0);
   add_AT_loc (die, DW_AT_data_member_location, loc_descr);
 }
@@ -5015,6 +6050,7 @@ add_data_member_location_attribute (die, decl)
    things can arise in GNU C when a constant is passed as an actual parameter
    to an inlined function.  They can also arise in C++ where declared
    constants do not necessarily get memory "homes".  */
+
 static void
 add_const_value_attribute (die, rtl)
      register dw_die_ref die;
@@ -5035,12 +6071,42 @@ add_const_value_attribute (die, rtl)
       /* Note that a CONST_DOUBLE rtx could represent either an integer or a
          floating-point constant.  A CONST_DOUBLE is used whenever the
          constant requires more than one word in order to be adequately
-         represented.  In all such cases, the original mode of the constant
-         value is preserved as the mode of the CONST_DOUBLE rtx, but for
-         simplicity we always just output CONST_DOUBLEs using 8 bytes.  */
-      add_AT_double (die, DW_AT_const_value,
-                    (unsigned) CONST_DOUBLE_HIGH (rtl),
-                    (unsigned) CONST_DOUBLE_LOW (rtl));
+         represented.  We output CONST_DOUBLEs as blocks.  */
+      {
+       register enum machine_mode mode = GET_MODE (rtl);
+
+       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+         {
+           register unsigned length = GET_MODE_SIZE (mode) / sizeof (long);
+           long array[4];
+           REAL_VALUE_TYPE rv;
+
+           REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
+           switch (mode)
+             {
+             case SFmode:
+               REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]);
+               break;
+
+             case DFmode:
+               REAL_VALUE_TO_TARGET_DOUBLE (rv, array);
+               break;
+
+             case XFmode:
+             case TFmode:
+               REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array);
+               break;
+
+             default:
+               abort ();
+             }
+
+           add_AT_float (die, DW_AT_const_value, length, array);
+         }
+       else
+         add_AT_long_long (die, DW_AT_const_value,
+                           CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
+      }
       break;
 
     case CONST_STRING:
@@ -5086,6 +6152,7 @@ add_const_value_attribute (die, rtl)
    constant value which can be passed into an inlined function is a constant
    pointer.  This can happen for example if an actual argument in an inlined
    function call evaluates to a compile-time constant address.  */
+
 static void
 add_location_or_const_value_attribute (die, decl)
      register dw_die_ref die;
@@ -5096,80 +6163,84 @@ add_location_or_const_value_attribute (die, decl)
   register tree passed_type;
 
   if (TREE_CODE (decl) == ERROR_MARK)
-    {
-      return;
-    }
-  if ((TREE_CODE (decl) != VAR_DECL)
-      && (TREE_CODE (decl) != PARM_DECL))
-    {
-      /* Should never happen.  */
-      abort ();
-      return;
-    }
+    return;
+
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL)
+    abort ();
+
   /* Here we have to decide where we are going to say the parameter "lives"
      (as far as the debugger is concerned).  We only have a couple of
      choices.  GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.
+
      DECL_RTL normally indicates where the parameter lives during most of the 
-     activation of the function.  If optimization is enabled however, this
+     activation of the function.  If optimization is enabled however, this
      could be either NULL or else a pseudo-reg.  Both of those cases indicate 
      that the parameter doesn't really live anywhere (as far as the code
      generation parts of GCC are concerned) during most of the function's
      activation.  That will happen (for example) if the parameter is never
-     referenced within the function.  We could just generate a location
-     descriptor here for all non-NULL non-pseudo values of DECL_RTL and
-     ignore all of the rest, but we can be a little nicer than that if we
-     also consider DECL_INCOMING_RTL in cases where DECL_RTL is NULL or is a
-     pseudo-reg. Note however that we can only get away with using
-     DECL_INCOMING_RTL as a backup substitute for DECL_RTL in certain limited 
-     cases.  In cases where DECL_ARG_TYPE(decl) indicates the same type as
-     TREE_TYPE(decl) we can be sure that the parameter was passed using the
-     same type as it is declared to have within the function, and that its
-     DECL_INCOMING_RTL points us to a place where a value of that type is
-     passed.  In cases where DECL_ARG_TYPE(decl) and TREE_TYPE(decl) are
-     different types however, we cannot (in general) use DECL_INCOMING_RTL as 
-     a backup substitute for DECL_RTL because in these cases,
-     DECL_INCOMING_RTL points us to a value of some type which is *different* 
-     from the type of the parameter itself.  Thus, if we tried to use
-     DECL_INCOMING_RTL to generate a location attribute in such cases, the
-     debugger would end up (for example) trying to fetch a `float' from a
-     place which actually contains the first part of a `double'.  That would
-     lead to really incorrect and confusing output at debug-time, and we
-     don't want that now do we? So in general, we DO NOT use
-     DECL_INCOMING_RTL as a backup for DECL_RTL in cases where
-     DECL_ARG_TYPE(decl) != TREE_TYPE(decl).  There are a couple of cute
-     exceptions however.  On little-endian machines we can get away with
-     using DECL_INCOMING_RTL even when DECL_ARG_TYPE(decl) is not the same as 
-     TREE_TYPE(decl) but only when DECL_ARG_TYPE(decl) is an integral type
-     which is smaller than TREE_TYPE(decl). These cases arise when (on a
-     little-endian machine) a non-prototyped function has a parameter
-     declared to be of type `short' or `char'.  In such cases,
-     TREE_TYPE(decl) will be `short' or `char', DECL_ARG_TYPE(decl) will be
-     `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
-     passed `int' value.  If the debugger then uses that address to fetch a
-     `short' or a `char' (on a little-endian machine) the result will be the
-     correct data, so we allow for such exceptional cases below. Note that
-     our goal here is to describe the place where the given formal parameter
-     lives during most of the function's activation (i.e. between the end of
-     the prologue and the start of the epilogue).  We'll do that as best as
-     we can. Note however that if the given formal parameter is modified
-     sometime during the execution of the function, then a stack backtrace
-     (at debug-time) will show the function as having been called with the
-     *new* value rather than the value which was originally passed in.  This
-     happens rarely enough that it is not a major problem, but it *is* a
-     problem, and I'd like to fix it.  A future version of dwarfout.c may
-     generate two additional attributes for any given DW_TAG_formal_parameter 
-     DIE which will describe the "passed type" and the "passed location" for
-     the given formal parameter in addition to the attributes we now generate 
-     to indicate the "declared type" and the "active location" for each
-     parameter.  This additional set of attributes could be used by debuggers 
-     for stack backtraces. Separately, note that sometimes DECL_RTL can be
-     NULL and DECL_INCOMING_RTL can be NULL also.  This happens (for example) 
-     for inlined-instances of inline function formal parameters which are
-     never referenced.  This really shouldn't be happening.  All PARM_DECL
-     nodes should get valid non-NULL DECL_INCOMING_RTL values, but
-     integrate.c doesn't currently generate these values for inlined
-     instances of inline function parameters, so when we see such cases, we
-     are just SOL (shit-out-of-luck) for the time being (until integrate.c
+     referenced within the function.
+
+     We could just generate a location descriptor here for all non-NULL
+     non-pseudo values of DECL_RTL and ignore all of the rest, but we can be
+     a little nicer than that if we also consider DECL_INCOMING_RTL in cases
+     where DECL_RTL is NULL or is a pseudo-reg.
+
+     Note however that we can only get away with using DECL_INCOMING_RTL as
+     a backup substitute for DECL_RTL in certain limited cases.  In cases
+     where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl),
+     we can be sure that the parameter was passed using the same type as it is
+     declared to have within the function, and that its DECL_INCOMING_RTL
+     points us to a place where a value of that type is passed.
+
+     In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different,
+     we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL
+     because in these cases DECL_INCOMING_RTL points us to a value of some
+     type which is *different* from the type of the parameter itself.  Thus,
+     if we tried to use DECL_INCOMING_RTL to generate a location attribute in
+     such cases, the debugger would end up (for example) trying to fetch a
+     `float' from a place which actually contains the first part of a
+     `double'.  That would lead to really incorrect and confusing
+     output at debug-time.
+
+     So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL
+     in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl).  There
+     are a couple of exceptions however.  On little-endian machines we can
+     get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is
+     not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is
+     an integral type that is smaller than TREE_TYPE (decl). These cases arise
+     when (on a little-endian machine) a non-prototyped function has a
+     parameter declared to be of type `short' or `char'.  In such cases,
+     TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will
+     be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
+     passed `int' value.  If the debugger then uses that address to fetch
+     a `short' or a `char' (on a little-endian machine) the result will be
+     the correct data, so we allow for such exceptional cases below.
+
+     Note that our goal here is to describe the place where the given formal
+     parameter lives during most of the function's activation (i.e. between
+     the end of the prologue and the start of the epilogue).  We'll do that
+     as best as we can. Note however that if the given formal parameter is
+     modified sometime during the execution of the function, then a stack
+     backtrace (at debug-time) will show the function as having been
+     called with the *new* value rather than the value which was
+     originally passed in.  This happens rarely enough that it is not
+     a major problem, but it *is* a problem, and I'd like to fix it.
+
+     A future version of dwarf2out.c may generate two additional
+     attributes for any given DW_TAG_formal_parameter DIE which will
+     describe the "passed type" and the "passed location" for the
+     given formal parameter in addition to the attributes we now
+     generate to indicate the "declared type" and the "active
+     location" for each parameter.  This additional set of attributes
+     could be used by debuggers for stack backtraces. Separately, note
+     that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be
+     NULL also.  This happens (for example) for inlined-instances of
+     inline function formal parameters which are never referenced.
+     This really shouldn't be happening.  All PARM_DECL nodes should
+     get valid non-NULL DECL_INCOMING_RTL values, but integrate.c
+     doesn't currently generate these values for inlined instances of
+     inline function parameters, so when we see such cases, we are
+     just SOL (shit-out-of-luck) for the time being (until integrate.c
      gets fixed).  */
 
   /* Use DECL_RTL as the "location" unless we find something better.  */
@@ -5181,31 +6252,22 @@ add_location_or_const_value_attribute (die, decl)
        {
          declared_type = type_main_variant (TREE_TYPE (decl));
          passed_type = type_main_variant (DECL_ARG_TYPE (decl));
-         /* This decl represents a formal parameter which was
-            optimized out.
 
+         /* This decl represents a formal parameter which was optimized out.
             Note that DECL_INCOMING_RTL may be NULL in here, but we handle
             all* cases where (rtl == NULL_RTX) just below.  */
          if (declared_type == passed_type)
-           {
-             rtl = DECL_INCOMING_RTL (decl);
-           }
-         else if (!BYTES_BIG_ENDIAN)
-           {
-             if (TREE_CODE (declared_type) == INTEGER_TYPE)
-               {
-                 if (TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type))
-                   {
-                     rtl = DECL_INCOMING_RTL (decl);
-                   }
-               }
-           }
-         if (rtl == NULL_RTX)
-           {
-             return;
-           }
+           rtl = DECL_INCOMING_RTL (decl);
+         else if (! BYTES_BIG_ENDIAN
+                  && TREE_CODE (declared_type) == INTEGER_TYPE
+                  && TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type))
+               rtl = DECL_INCOMING_RTL (decl);
        }
     }
+
+  if (rtl == NULL_RTX)
+    return;
+
   switch (GET_CODE (rtl))
     {
     case CONST_INT:
@@ -5226,32 +6288,31 @@ add_location_or_const_value_attribute (die, decl)
       break;
 
     default:
-      abort ();                        /* Should never happen.  */
+      abort ();
     }
 }
 
 /* Generate an DW_AT_name attribute given some string value to be included as
    the value of the attribute.  */
-inline void
+
+static inline void
 add_name_attribute (die, name_string)
      register dw_die_ref die;
      register char *name_string;
 {
-  if (name_string && *name_string)
-    {
-      add_AT_string (die, DW_AT_name, name_string);
-    }
+  if (name_string != NULL && *name_string != 0)
+    add_AT_string (die, DW_AT_name, name_string);
 }
 
 /* Given a tree node describing an array bound (either lower or upper) output
    a representation for that bound.  */
+
 static void
 add_bound_info (subrange_die, bound_attr, bound)
      register dw_die_ref subrange_die;
      register enum dwarf_attribute bound_attr;
      register tree bound;
 {
-  register dw_loc_descr_ref bound_loc = NULL;
   register unsigned bound_value = 0;
   switch (TREE_CODE (bound))
     {
@@ -5261,58 +6322,61 @@ add_bound_info (subrange_die, bound_attr, bound)
     /* All fixed-bounds are represented by INTEGER_CST nodes.        */
     case INTEGER_CST:
       bound_value = TREE_INT_CST_LOW (bound);
-      /* TODO: we need to check for C language below, or some flag
-        derived from the language.  C implies a lower bound of 0.   */
-      if (!(bound_attr == DW_AT_lower_bound && bound_value == 0))
-       {
-         add_AT_unsigned (subrange_die, bound_attr, bound_value);
-        }
+      if (bound_attr == DW_AT_lower_bound
+         && ((is_c_family () && bound_value == 0)
+             || (is_fortran () && bound_value == 1)))
+       /* use the default */;
+      else
+       add_AT_unsigned (subrange_die, bound_attr, bound_value);
       break;
 
-    /* Dynamic bounds may be represented by NOP_EXPR nodes containing
-       SAVE_EXPR nodes.  */
+    case CONVERT_EXPR:
     case NOP_EXPR:
-      bound = TREE_OPERAND (bound, 0);
-      /* ... fall thru...  */
-
+    case NON_LVALUE_EXPR:
+      add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
+      break;
+      
     case SAVE_EXPR:
       /* If optimization is turned on, the SAVE_EXPRs that describe how to
-         access the upper bound values are essentially bogus. They only
-         describe (at best) how to get at these values at the points in the
-         generated code right after they have just been computed.  Worse yet, 
-         in the typical case, the upper bound values will not even *be*
-         computed in the optimized code, so these SAVE_EXPRs are entirely
-         bogus. In order to compensate for this fact, we check here to see if
-         optimization is enabled, and if so, we effectively create an empty
-         location description for the (unknown and unknowable) upper bound.
-         This should not cause too much trouble for existing (stupid?)
-         debuggers because they have to deal with empty upper bounds location
-         descriptions anyway in order to be able to deal with incomplete array 
-         types.  Of course an intelligent debugger (GDB?) should be able to
-         comprehend that a missing upper bound specification in a array type
-         used for a storage class `auto' local array variable indicates that
-         the upper bound is both unknown (at compile- time) and unknowable (at
-         run-time) due to optimization.  */
-      if (!optimize)
+         access the upper bound values may be bogus.  If they refer to a
+         register, they may only describe how to get at these values at the
+         points in the generated code right after they have just been
+         computed.  Worse yet, in the typical case, the upper bound values
+         will not even *be* computed in the optimized code (though the
+         number of elements will), so these SAVE_EXPRs are entirely
+         bogus. In order to compensate for this fact, we check here to see
+         if optimization is enabled, and if so, we don't add an attribute
+         for the (unknown and unknowable) upper bound.  This should not
+         cause too much trouble for existing (stupid?)  debuggers because
+         they have to deal with empty upper bounds location descriptions
+         anyway in order to be able to deal with incomplete array types.
+         Of course an intelligent debugger (GDB?)  should be able to
+         comprehend that a missing upper bound specification in a array
+         type used for a storage class `auto' local array variable
+         indicates that the upper bound is both unknown (at compile- time)
+         and unknowable (at run-time) due to optimization.
+
+        We assume that a MEM rtx is safe because gcc wouldn't put the
+        value there unless it was going to be used repeatedly in the
+        function, i.e. for cleanups.  */
+      if (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM)
        {
-         bound_loc = mem_loc_descriptor (
-                                     eliminate_regs (SAVE_EXPR_RTL (bound),
-                                                     0, NULL_RTX));
+         register dw_die_ref ctx = lookup_decl_die (current_function_decl);
+         register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx);
+         add_AT_flag (decl_die, DW_AT_artificial, 1);
+         add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
+         add_location_attribute (decl_die, SAVE_EXPR_RTL (bound));
+         add_AT_die_ref (subrange_die, bound_attr, decl_die);
        }
-      else
-       {
-         bound_loc = NULL;
-       }
-      add_AT_loc (subrange_die, bound_attr, bound_loc);
-      break;
 
-    default:
-      abort ();
+      /* Else leave out the attribute.  */
+      break;
     }
 }
 
 /* Note that the block of subscript information for an array type also
    includes information about the element type of type given array type.  */
+
 static void
 add_subscript_info (type_die, type)
      register dw_die_ref type_die;
@@ -5330,6 +6394,7 @@ add_subscript_info (type_die, type)
      compression in C (because there is no difference between an array or
      arrays and a multidimensional array in C) but for other source languages 
      (e.g. Ada) we probably shouldn't do this.  */
+
   /* ??? The SGI dwarf reader fails for multidimensional arrays with a
      const enum type.  E.g. const enum machine_mode insn_operand_mode[2][10].
      We work around this by disabling this feature.  See also
@@ -5352,28 +6417,20 @@ add_subscript_info (type_die, type)
          lower = TYPE_MIN_VALUE (domain);
          upper = TYPE_MAX_VALUE (domain);
 
-         /* TODO: establish DW_AT_type for the basis type a byte_size
-            attribute if the byte size is non-standard */
+         /* define the index type.  */
+         if (TREE_TYPE (domain))
+           add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0,
+                               type_die);
+
          add_bound_info (subrange_die, DW_AT_lower_bound, lower);
          add_bound_info (subrange_die, DW_AT_upper_bound, upper);
        }
       else
-       {
-         /* We have an array type with an unspecified length. For C and C++
-            we can assume that this really means that (a) the index type is
-            an integral type, and (b) the lower bound is zero. Note that
-            Dwarf defines the representation of an unspecified (upper) bound 
-            as being a zero-length location description.  */
-
-         /* define the (assumed) index type.  */
-         add_AT_die_ref (subrange_die, DW_AT_type, int_base_type_die);
+       /* We have an array type with an unspecified length.  The DWARF-2
+            spec does not say how to handle this; let's just leave out the
+            bounds.  */
+       ;
 
-         /* Add the (assumed) lower bound (constant) value.   */
-         add_AT_unsigned (subrange_die, DW_AT_lower_bound, 0);
-
-         /* Add the (empty) location description for the upper bound.  */
-         add_AT_loc (subrange_die, DW_AT_upper_bound, NULL);
-       }
 #ifndef MIPS_DEBUGGING_INFO
     }
 #endif
@@ -5421,18 +6478,19 @@ add_byte_size_attribute (die, tree_node)
    "containing object" for the bit-field to the highest order bit of the
    bit-field itself.
 
-   For any given bit-field, the "containing object" is a hypothetical object (of
-   some integral or enum type) within which the given bit-field lives.  The
-   type of this hypothetical "containing object" is always the same as the
-   declared type of the individual bit-field itself.
-   The determination of the exact location of the "containing object" for a
-   bit-field is rather complicated.  It's handled by the `field_byte_offset'
-   function (above).
+   For any given bit-field, the "containing object" is a hypothetical
+   object (of some integral or enum type) within which the given bit-field
+   lives.  The type of this hypothetical "containing object" is always the
+   same as the declared type of the individual bit-field itself.  The
+   determination of the exact location of the "containing object" for a
+   bit-field is rather complicated.  It's handled by the
+   `field_byte_offset' function (above).
 
    Note that it is the size (in bytes) of the hypothetical "containing object"
    which will be given in the DW_AT_byte_size attribute for this bit-field.
    (See `byte_size_attribute' above).  */
-inline void
+
+static inline void
 add_bit_offset_attribute (die, decl)
      register dw_die_ref die;
      register tree decl;
@@ -5452,9 +6510,8 @@ add_bit_offset_attribute (die, decl)
      encounter such things, just return without generating any attribute
      whatsoever.  */
   if (TREE_CODE (bitpos_tree) != INTEGER_CST)
-    {
-      return;
-    }
+    return;
+
   bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
 
   /* Note that the bit offset is always the distance (in bits) from the
@@ -5465,24 +6522,26 @@ add_bit_offset_attribute (die, decl)
   highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
   highest_order_field_bit_offset = bitpos_int;
 
-  if (!BYTES_BIG_ENDIAN)
+  if (! BYTES_BIG_ENDIAN)
     {
       highest_order_field_bit_offset
        += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl));
 
       highest_order_object_bit_offset += simple_type_size_in_bits (type);
     }
-  bit_offset =
-    (!BYTES_BIG_ENDIAN
-     ? highest_order_object_bit_offset - highest_order_field_bit_offset
-     : highest_order_field_bit_offset - highest_order_object_bit_offset);
+
+  bit_offset
+    = (! BYTES_BIG_ENDIAN
+       ? highest_order_object_bit_offset - highest_order_field_bit_offset
+       : highest_order_field_bit_offset - highest_order_object_bit_offset);
 
   add_AT_unsigned (die, DW_AT_bit_offset, bit_offset);
 }
 
 /* For a FIELD_DECL node which represents a bit field, output an attribute
    which specifies the length in bits of the given field.  */
-inline void
+
+static inline void
 add_bit_size_attribute (die, decl)
      register dw_die_ref die;
      register tree decl;
@@ -5493,98 +6552,97 @@ add_bit_size_attribute (die, decl)
                   (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)));
 }
 
-inline void
-add_member_attribute (die, context)
-     register dw_die_ref die;
-     register tree context;
-{
-  register dw_die_ref type_die;
-
-  /* Generate this attribute only for members in C++.  */
-  if (context != NULL && is_tagged_type (context))
-    {
-      type_die = lookup_type_die (context);
-      add_AT_die_ref (die, DW_AT_member, type_die);
-    }
-}
-
-/* If the compiled language is GNU C, then add a 'prototyped'
+/* If the compiled language is ANSI C, then add a 'prototyped'
    attribute, if arg types are given for the parameters of a function.  */
-inline void
+
+static inline void
 add_prototyped_attribute (die, func_type)
      register dw_die_ref die;
      register tree func_type;
 {
-  if ((strcmp (language_string, "GNU C") == 0)
-      && (TYPE_ARG_TYPES (func_type) != NULL))
-    {
-      add_AT_flag (die, DW_AT_prototyped, 0);
-    }
+  if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89
+      && TYPE_ARG_TYPES (func_type) != NULL)
+    add_AT_flag (die, DW_AT_prototyped, 1);
 }
 
 
 /* Add an 'abstract_origin' attribute below a given DIE.  The DIE is found
    by looking in either the type declaration or object declaration
    equate table.  */
-inline void
+
+static inline void
 add_abstract_origin_attribute (die, origin)
      register dw_die_ref die;
      register tree origin;
 {
   dw_die_ref origin_die = NULL;
   if (TREE_CODE_CLASS (TREE_CODE (origin)) == 'd')
-    {
-      origin_die = lookup_decl_die (origin);
-    }
+    origin_die = lookup_decl_die (origin);
   else if (TREE_CODE_CLASS (TREE_CODE (origin)) == 't')
-    {
-      origin_die = lookup_type_die (origin);
-    }
+    origin_die = lookup_type_die (origin);
+
   add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
 }
 
-/* If the compiled source program is  C++, define the pure_virtual
-   attribute.  */
-inline void
+/* We do not currently support the pure_virtual attribute.  */
+
+static inline void
 add_pure_or_virtual_attribute (die, func_decl)
      register dw_die_ref die;
      register tree func_decl;
 {
-  if (DECL_VIRTUAL_P (func_decl))
+  if (DECL_VINDEX (func_decl))
     {
-      if ((strcmp (language_string, "GNU C++") == 0)
-         && (DECL_VIRTUAL_P (func_decl)))
-       {
-         add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_pure_virtual);
-       }
-      else
-       {
-         add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
-       }
+      add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+      add_AT_loc (die, DW_AT_vtable_elem_location,
+                 new_loc_descr (DW_OP_constu,
+                                TREE_INT_CST_LOW (DECL_VINDEX (func_decl)),
+                                0));
+
+      /* GNU extension: Record what type this method came from originally.  */
+      if (debug_info_level > DINFO_LEVEL_TERSE)
+       add_AT_die_ref (die, DW_AT_containing_type,
+                       lookup_type_die (DECL_CONTEXT (func_decl)));
     }
 }
 \f
-/********************* utility routines for DIEs *************************/
+/* Add source coordinate attributes for the given decl.  */
+
+static void
+add_src_coords_attributes (die, decl)
+     register dw_die_ref die;
+     register tree decl;
+{
+  register unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
+
+  add_AT_unsigned (die, DW_AT_decl_file, file_index);
+  add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
+}
 
 /* Add an DW_AT_name attribute and source coordinate attribute for the
    given decl, but only if it actually has a name.  */
+
 static void
 add_name_and_src_coords_attributes (die, decl)
      register dw_die_ref die;
      register tree decl;
 {
-  register tree decl_name = DECL_NAME (decl);
-  register unsigned file_index;
-  if (decl_name && IDENTIFIER_POINTER (decl_name))
+  register tree decl_name;
+
+  decl_name = DECL_NAME (decl); 
+  if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
     {
-      add_name_attribute (die, IDENTIFIER_POINTER (decl_name));
-      file_index = lookup_filename (DECL_SOURCE_FILE (decl));
-      add_AT_unsigned (die, DW_AT_decl_file, file_index);
-      add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
+      add_name_attribute (die, dwarf2_name (decl, 0));
+      add_src_coords_attributes (die, decl);
+      if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
+         && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
+       add_AT_string (die, DW_AT_MIPS_linkage_name,
+                      IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
     }
 }
 
 /* Push a new declaration scope. */
+
 static void
 push_decl_scope (scope)
      tree scope;
@@ -5593,49 +6651,63 @@ push_decl_scope (scope)
   if (decl_scope_table_allocated == decl_scope_depth)
     {
       decl_scope_table_allocated += DECL_SCOPE_TABLE_INCREMENT;
-      decl_scope_table = (tree *) xrealloc (decl_scope_table,
-                          decl_scope_table_allocated * sizeof (tree));
+      decl_scope_table
+       = (tree *) xrealloc (decl_scope_table,
+                            decl_scope_table_allocated * sizeof (tree));
     }
+
   decl_scope_table[decl_scope_depth++] = scope;
 }
 
 /* Return the DIE for the scope the immediately contains this declaration.  */
+
 static dw_die_ref
-scope_die_for_type (type, context_die)
-    register tree type
+scope_die_for (t, context_die)
+    register tree t; 
     register dw_die_ref context_die;
 {
   register dw_die_ref scope_die = NULL;
   register tree containing_scope;
   register unsigned long i;
 
+  /* Function-local tags and functions get stuck in limbo until they are
+     fixed up by decls_for_scope.  */
+  if (context_die == NULL
+      && (TREE_CODE (t) == FUNCTION_DECL || is_tagged_type (t)))
+    return NULL;
+
   /* Walk back up the declaration tree looking for a place to define
      this type.  */
-  containing_scope = TYPE_CONTEXT (type);
-  if (containing_scope == NULL)
-    {
-      scope_die = comp_unit_die;
-    }
+  if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+    containing_scope = TYPE_CONTEXT (t);
+  else if (TREE_CODE (t) == FUNCTION_DECL && DECL_VINDEX (t))
+    containing_scope = decl_class_context (t);
+  else
+    containing_scope = DECL_CONTEXT (t);
+
+  if (containing_scope == NULL_TREE)
+    scope_die = comp_unit_die;
   else
     {
-      for (i = decl_scope_depth - 1, scope_die = context_die;
-          i >= 0
-          && scope_die != NULL
-          && decl_scope_table[i] != containing_scope;
-          --i, scope_die = scope_die->die_parent)
-       {
-         /* nothing */ ;
-       }
-      if (scope_die == NULL)
+      for (i = decl_scope_depth, scope_die = context_die;
+          i > 0 && decl_scope_table[i - 1] != containing_scope;
+          scope_die = scope_die->die_parent, --i)
+       ;
+
+      if (i == 0)
        {
-         scope_die = context_die;
+         assert (scope_die == comp_unit_die);
+         assert (TREE_CODE_CLASS (TREE_CODE (containing_scope)) == 't');
+         if (debug_info_level > DINFO_LEVEL_TERSE)
+           assert (TREE_ASM_WRITTEN (containing_scope));
        }
     }
+
   return scope_die;
 }
 
 /* Pop a declaration scope.  */
-inline void
+static inline void
 pop_decl_scope ()
 {
   assert (decl_scope_depth > 0);
@@ -5645,6 +6717,7 @@ pop_decl_scope ()
 /* Many forms of DIEs require a "type description" attribute.  This
    routine locates the proper "type descriptor" die for the type given
    by 'type', and adds an DW_AT_type attribute below the given die.  */
+
 static void
 add_type_attribute (object_die, type, decl_const, decl_volatile, context_die)
      register dw_die_ref object_die;
@@ -5654,36 +6727,35 @@ add_type_attribute (object_die, type, decl_const, decl_volatile, context_die)
      register dw_die_ref context_die;
 {
   register enum tree_code code  = TREE_CODE (type);
-  register dw_die_ref scope_die = NULL;
   register dw_die_ref type_die  = NULL;
 
+  /* If this type is an unnamed subtype of an integral or floating-point
+     type, use the inner type.  */
+  if ((code == INTEGER_TYPE || code == REAL_TYPE)
+      && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0)
+    type = TREE_TYPE (type), code = TREE_CODE (type);
+
   if (code == ERROR_MARK)
-    {
-      return;
-    }
+    return;
 
   /* Handle a special case.  For functions whose return type is void, we
      generate *no* type attribute.  (Note that no object may have type
      `void', so this only applies to function return types).  */
   if (code == VOID_TYPE)
-    {
-      return;
-    }
+    return;
 
-  scope_die = scope_die_for_type (type, context_die);
   type_die = modified_type_die (type,
                                decl_const || TYPE_READONLY (type),
                                decl_volatile || TYPE_VOLATILE (type),
-                               scope_die);
+                               context_die);
   if (type_die != NULL)
-    {
-      add_AT_die_ref (object_die, DW_AT_type, type_die);
-    }
+    add_AT_die_ref (object_die, DW_AT_type, type_die);
 }
 
 /* Given a tree pointer to a struct, class, union, or enum type node, return
    a pointer to the (string) tag name for the given type, or zero if the type
    was declared without a tag.  */
+
 static char *
 type_tag (type)
      register tree type;
@@ -5697,81 +6769,77 @@ type_tag (type)
       /* Find the IDENTIFIER_NODE for the type name.  */
       if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
        t = TYPE_NAME (type);
-#if 0
+
       /* The g++ front end makes the TYPE_NAME of *each* tagged type point to 
          a TYPE_DECL node, regardless of whether or not a `typedef' was
-         involved.  This is distinctly different from what the gcc front-end
-         does.  It always makes the TYPE_NAME for each tagged type be either
-         NULL (signifying an anonymous tagged type) or else a pointer to an
-         IDENTIFIER_NODE.  Obviously, we would like to generate correct Dwarf 
-         for both C and C++, but given this inconsistency in the TREE
-         representation of tagged types for C and C++ in the GNU front-ends,
-         we cannot support both languages correctly unless we introduce some
-         front-end specific code here, and rms objects to that, so we can
-         only generate correct Dwarf for one of these two languages.  C is
-         more important, so for now we'll do the right thing for C and let
-         g++ go fish.  */
-      else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)
+         involved.  */
+      else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+              && ! DECL_IGNORED_P (TYPE_NAME (type)))
        t = DECL_NAME (TYPE_NAME (type));
-#endif
+
       /* Now get the name as a string, or invent one.  */
       if (t != 0)
-       {
-         name = IDENTIFIER_POINTER (t);
-       }
+       name = IDENTIFIER_POINTER (t);
     }
+
   return (name == 0 || *name == '\0') ? 0 : name;
 }
 
 /* Return the type associated with a data member, make a special check
    for bit field types.  */
-inline tree
+
+static inline tree
 member_declared_type (member)
      register tree member;
 {
-  return (DECL_BIT_FIELD_TYPE (member))
-    ? DECL_BIT_FIELD_TYPE (member)
-    : TREE_TYPE (member);
+  return (DECL_BIT_FIELD_TYPE (member)
+         ? DECL_BIT_FIELD_TYPE (member)
+         : TREE_TYPE (member));
 }
 
-/* Get the function's label, as described by its RTL. This may be different
+/* Get the decl's label, as described by its RTL. This may be different
    from the DECL_NAME name used in the source file.  */
+
 static char *
-function_start_label (decl)
+decl_start_label (decl)
      register tree decl;
 {
   rtx x;
   char *fnname;
   x = DECL_RTL (decl);
   if (GET_CODE (x) != MEM)
-    {
-      abort ();
-    }
+    abort ();
+
   x = XEXP (x, 0);
   if (GET_CODE (x) != SYMBOL_REF)
-    {
-      abort ();
-    }
+    abort ();
+
   fnname = XSTR (x, 0);
   return fnname;
 }
 \f
-/******************************* DIE Generation *************************/
-
 /* These routines generate the internnal representation of the DIE's for
    the compilation unit.  Debugging information is collected by walking
-   the declaration trees passed in from dwarfout_file_scope_decl().  */
+   the declaration trees passed in from dwarf2out_decl().  */
 
 static void
 gen_array_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref scope_die = scope_die_for_type (type, context_die);
-  register dw_die_ref array_die = new_die (DW_TAG_array_type, scope_die);
+  register dw_die_ref scope_die = scope_die_for (type, context_die);
+  register dw_die_ref array_die;
   register tree element_type;
-  /* TODO: why a member_attribute under an array?
-     member_attribute (array_die, TYPE_CONTEXT (type)); */
+
+  /* ??? The SGI dwarf reader fails for array of array of enum types unless
+     the inner array type comes before the outer array type.  Thus we must
+     call gen_type_die before we call new_die.  See below also.  */
+#ifdef MIPS_DEBUGGING_INFO
+  gen_type_die (TREE_TYPE (type), context_die);
+#endif
+
+  array_die = new_die (DW_TAG_array_type, scope_die);
+
 #if 0
   /* We default the array ordering.  SDB will probably do
      the right things even if DW_AT_ordering is not present.  It's not even
@@ -5783,23 +6851,30 @@ gen_array_type_die (type, context_die)
   add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
 #endif
 
-  add_subscript_info (array_die, type);
+#ifdef MIPS_DEBUGGING_INFO
+  /* The SGI compilers handle arrays of unknown bound by setting
+     AT_declaration and not emitting any subrange DIEs.  */
+  if (! TYPE_DOMAIN (type))
+    add_AT_unsigned (array_die, DW_AT_declaration, 1);
+  else
+#endif
+    add_subscript_info (array_die, type);
 
   equate_type_number_to_die (type, array_die);
 
   /* Add representation of the type of the elements of this array type.  */
   element_type = TREE_TYPE (type);
+
   /* ??? The SGI dwarf reader fails for multidimensional arrays with a
      const enum type.  E.g. const enum machine_mode insn_operand_mode[2][10].
      We work around this by disabling this feature.  See also
      add_subscript_info.  */
 #ifndef MIPS_DEBUGGING_INFO
   while (TREE_CODE (element_type) == ARRAY_TYPE)
-    {
-      element_type = TREE_TYPE (element_type);
-    }
-#endif
+    element_type = TREE_TYPE (element_type);
+
   gen_type_die (element_type, context_die);
+#endif
 
   add_type_attribute (array_die, element_type, 0, 0, context_die);
 }
@@ -5809,10 +6884,10 @@ gen_set_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref type_die;
-  type_die = new_die (DW_TAG_set_type, scope_die_for_type (type, context_die));
+  register dw_die_ref type_die
+    = new_die (DW_TAG_set_type, scope_die_for (type, context_die));
+
   equate_type_number_to_die (type, type_die);
-  add_member_attribute (type_die, TYPE_CONTEXT (type));
   add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die);
 }
 
@@ -5824,111 +6899,156 @@ gen_entry_point_die (decl, context_die)
   register tree origin = decl_ultimate_origin (decl);
   register dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die);
   if (origin != NULL)
-    {
-      add_abstract_origin_attribute (decl_die, origin);
-    }
+    add_abstract_origin_attribute (decl_die, origin);
   else
     {
       add_name_and_src_coords_attributes (decl_die, decl);
-      add_member_attribute (decl_die, DECL_CONTEXT (decl));
       add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
                          0, 0, context_die);
     }
+
   if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die (decl, decl_die);
+  else
+    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
+}
+
+/* Remember a type in the pending_types_list.  */
+
+static void
+pend_type (type)
+     register tree type;
+{
+  if (pending_types == pending_types_allocated)
     {
-      equate_decl_number_to_die (decl, decl_die);
+      pending_types_allocated += PENDING_TYPES_INCREMENT;
+      pending_types_list
+       = (tree *) xrealloc (pending_types_list,
+                            sizeof (tree) * pending_types_allocated);
     }
-  else
+
+  pending_types_list[pending_types++] = type;
+}
+
+/* Output any pending types (from the pending_types list) which we can output
+   now (taking into account the scope that we are working on now).
+
+   For each type output, remove the given type from the pending_types_list
+   *before* we try to output it.  */
+
+static void
+output_pending_types_for_scope (context_die)
+     register dw_die_ref context_die;
+{
+  register tree type;
+
+  while (pending_types)
     {
-      add_AT_lbl_id (decl_die, DW_AT_low_pc, function_start_label (decl));
+      --pending_types;
+      type = pending_types_list[pending_types];
+      gen_type_die (type, context_die);
+      assert (TREE_ASM_WRITTEN (type));
     }
 }
 
 /* Generate a DIE to represent an inlined instance of an enumeration type.  */
+
 static void
 gen_inlined_enumeration_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref type_die;
-  type_die = new_die (DW_TAG_enumeration_type,
-                     scope_die_for_type (type, context_die));
+  register dw_die_ref type_die = new_die (DW_TAG_enumeration_type,
+                                         scope_die_for (type, context_die));
+
   assert (TREE_ASM_WRITTEN (type));
   add_abstract_origin_attribute (type_die, type);
 }
 
 /* Generate a DIE to represent an inlined instance of a structure type.  */
+
 static void
 gen_inlined_structure_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref type_die;
-  type_die = new_die (DW_TAG_structure_type,
-                     scope_die_for_type (type, context_die));
+  register dw_die_ref type_die = new_die (DW_TAG_structure_type,
+                                         scope_die_for (type, context_die));
+
   assert (TREE_ASM_WRITTEN (type));
   add_abstract_origin_attribute (type_die, type);
 }
 
 /* Generate a DIE to represent an inlined instance of a union type.  */
+
 static void
 gen_inlined_union_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref type_die;
-  type_die = new_die (DW_TAG_union_type,
-                     scope_die_for_type (type, context_die));
+  register dw_die_ref type_die = new_die (DW_TAG_union_type,
+                                         scope_die_for (type, context_die));
+
   assert (TREE_ASM_WRITTEN (type));
   add_abstract_origin_attribute (type_die, type);
 }
 
 /* Generate a DIE to represent an enumeration type.  Note that these DIEs
    include all of the information about the enumeration values also. Each
-   enumerated type name/value is listed as a child of the enumerated type DIE */
+   enumerated type name/value is listed as a child of the enumerated type
+   DIE.  */
+
 static void
-gen_enumeration_type_die (type, is_complete, context_die)
+gen_enumeration_type_die (type, context_die)
      register tree type;
-     register unsigned is_complete;
      register dw_die_ref context_die;
 {
-  register dw_die_ref type_die;
-  register dw_die_ref enum_die;
-  register tree link;
-  type_die = lookup_type_die (type);
+  register dw_die_ref type_die = lookup_type_die (type);
+
   if (type_die == NULL)
     {
       type_die = new_die (DW_TAG_enumeration_type,
-                         scope_die_for_type (type, context_die));
+                         scope_die_for (type, context_die));
       equate_type_number_to_die (type, type_die);
       add_name_attribute (type_die, type_tag (type));
-      add_member_attribute (type_die, TYPE_CONTEXT (type));
     }
-  if (is_complete)
+  else if (! TYPE_SIZE (type))
+    return;
+  else
+    remove_AT (type_die, DW_AT_declaration);
+
+  /* Handle a GNU C/C++ extension, i.e. incomplete enum types.  If the
+     given enum type is incomplete, do not generate the DW_AT_byte_size
+     attribute or the DW_AT_element_list attribute.  */
+  if (TYPE_SIZE (type))
     {
-      /* Handle a GNU C/C++ extension, i.e. incomplete enum types.  If the
-         given enum type is incomplete, do not generate the DW_AT_byte_size
-         attribute or the DW_AT_element_list attribute.  */
-      if (TYPE_SIZE (type))
+      register tree link;
+
+      TREE_ASM_WRITTEN (type) = 1;
+      add_byte_size_attribute (type_die, type);
+      if (type_tag (type))
+       add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+
+      for (link = TYPE_FIELDS (type);
+          link != NULL; link = TREE_CHAIN (link))
        {
-         add_byte_size_attribute (type_die, type);
-         for (link = TYPE_FIELDS (type);
-              link != NULL; link = TREE_CHAIN (link))
-           {
-             enum_die = new_die (DW_TAG_enumerator, type_die);
-             add_name_attribute (enum_die,
-                                 IDENTIFIER_POINTER (TREE_PURPOSE (link)));
-             add_AT_unsigned (enum_die, DW_AT_const_value,
+         register dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die);
+
+         add_name_attribute (enum_die,
+                             IDENTIFIER_POINTER (TREE_PURPOSE (link)));
+         add_AT_unsigned (enum_die, DW_AT_const_value,
                           (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link)));
-           }
        }
     }
+  else
+    add_AT_flag (type_die, DW_AT_declaration, 1);
 }
 
 
 /* Generate a DIE to represent either a real live formal parameter decl or to
    represent just the type of some formal parameter position in some function
    type.
+
    Note that this routine is a bit unusual because its argument may be a
    ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which
    represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE
@@ -5937,23 +7057,22 @@ gen_enumeration_type_die (type, is_complete, context_die)
    it's the latter, then this function is only being called to output a
    DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
    argument type of some subprogram type.  */
-static void
+
+static dw_die_ref
 gen_formal_parameter_die (node, context_die)
      register tree node;
      register dw_die_ref context_die;
 {
-  register dw_die_ref parm_die = new_die (DW_TAG_formal_parameter,
-                                         context_die);
+  register dw_die_ref parm_die
+    = new_die (DW_TAG_formal_parameter, context_die);
   register tree origin;
+
   switch (TREE_CODE_CLASS (TREE_CODE (node)))
     {
-      /* We were called with some kind of a ..._DECL node.  */
     case 'd':
       origin = decl_ultimate_origin (node);
       if (origin != NULL)
-       {
-         add_abstract_origin_attribute (parm_die, origin);
-       }
+       add_abstract_origin_attribute (parm_die, origin);
       else
        {
          add_name_and_src_coords_attributes (parm_die, node);
@@ -5961,30 +7080,31 @@ gen_formal_parameter_die (node, context_die)
                              TREE_READONLY (node),
                              TREE_THIS_VOLATILE (node),
                              context_die);
+         if (DECL_ARTIFICIAL (node))
+           add_AT_flag (parm_die, DW_AT_artificial, 1);
        }
-      if (DECL_ABSTRACT (node))
-       {
-         equate_decl_number_to_die (node, parm_die);
-       }
-      else
-       {
-         add_location_or_const_value_attribute (parm_die, node);
-       }
+
+      equate_decl_number_to_die (node, parm_die);
+      if (! DECL_ABSTRACT (node))
+       add_location_or_const_value_attribute (parm_die, node);
+
       break;
 
-      /* We were called with some kind of a ..._TYPE node.  */
     case 't':
+      /* We were called with some kind of a ..._TYPE node.  */
       add_type_attribute (parm_die, node, 0, 0, context_die);
       break;
 
-      /* Should never happen.  */
     default:
       abort ();
     }
+
+  return parm_die;
 }
 
 /* Generate a special type of DIE used as a stand-in for a trailing ellipsis
    at the end of an (ANSI prototyped) formal parameters list.  */
+
 static void
 gen_unspecified_parameters_die (decl_or_type, context_die)
      register tree decl_or_type;
@@ -5992,31 +7112,18 @@ gen_unspecified_parameters_die (decl_or_type, context_die)
 {
   register dw_die_ref parm_die = new_die (DW_TAG_unspecified_parameters,
                                          context_die);
-  /* This kludge is here only for the sake of being compatible with what the
-     USL CI5 C compiler does.  The specification of Dwarf Version 1 doesn't
-     say that DW_TAG_unspecified_parameters DIEs should contain any
-     attributes other than the DW_AT_sibling attribute, but they are
-     certainly allowed to contain additional attributes, and the CI5 compiler 
-     generates DW_AT_name, DW_AT_base_type, and DW_AT_location attributes
-     within DW_TAG_unspecified_parameters DIEs which appear in the child
-     lists for DIEs representing function definitions, so we do likewise
-     here.  */
-  if (TREE_CODE (decl_or_type) == FUNCTION_DECL
-      && DECL_INITIAL (decl_or_type))
-    {
-      add_name_attribute (parm_die, "...");
-      add_AT_die_ref (parm_die, DW_AT_type, int_base_type_die);
-    }
 }
 
 /* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a
    DW_TAG_unspecified_parameters DIE) to represent the types of the formal
    parameters as specified in some function type specification (except for
    those which appear as part of a function *definition*).
-   Note that we must be careful here to output all of the parameter DIEs before*
+
+   Note we must be careful here to output all of the parameter DIEs before*
    we output any DIEs needed to represent the types of the formal parameters.
    This keeps svr4 SDB happy because it (incorrectly) thinks that the first
    non-parameter DIE it sees ends the formal parameter list.  */
+
 static void
 gen_formal_types_die (function_or_method_type, context_die)
      register tree function_or_method_type;
@@ -6026,6 +7133,7 @@ gen_formal_types_die (function_or_method_type, context_die)
   register tree formal_type = NULL;
   register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
 
+#if 0
   /* In the case where we are generating a formal types list for a C++
      non-static member function type, skip over the first thing on the
      TYPE_ARG_TYPES list because it only represents the type of the hidden
@@ -6036,17 +7144,23 @@ gen_formal_types_die (function_or_method_type, context_die)
      DW_TAG_subroutine_type DIE.  */
   if (TREE_CODE (function_or_method_type) == METHOD_TYPE)
     first_parm_type = TREE_CHAIN (first_parm_type);
+#endif
 
   /* Make our first pass over the list of formal parameter types and output a 
      DW_TAG_formal_parameter DIE for each one.  */
   for (link = first_parm_type; link; link = TREE_CHAIN (link))
     {
+      register dw_die_ref parm_die;
+      
       formal_type = TREE_VALUE (link);
       if (formal_type == void_type_node)
        break;
 
       /* Output a (nameless) DIE to represent the formal parameter itself.  */
-      gen_formal_parameter_die (formal_type, context_die);
+      parm_die = gen_formal_parameter_die (formal_type, context_die);
+      if (TREE_CODE (function_or_method_type) == METHOD_TYPE
+         && link == first_parm_type)
+       add_AT_flag (parm_die, DW_AT_artificial, 1);
     }
 
   /* If this function type has an ellipsis, add a
@@ -6064,12 +7178,13 @@ gen_formal_types_die (function_or_method_type, context_die)
       if (formal_type == void_type_node)
        break;
 
-      gen_type_die (formal_type, function_or_method_type, context_die);
+      gen_type_die (formal_type, context_die);
     }
 }
 
 /* Generate a DIE to represent a declared function (either file-scope or
    block-local).  */
+
 static void
 gen_subprogram_die (decl, context_die)
      register tree decl;
@@ -6077,66 +7192,153 @@ gen_subprogram_die (decl, context_die)
 {
   char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
   register tree origin = decl_ultimate_origin (decl);
-  register dw_die_ref subr_die = new_die (DW_TAG_subprogram, context_die);
+  register dw_die_ref subr_die;
   register dw_loc_descr_ref fp_loc = NULL;
-  register unsigned fp_reg;
-  register tree type;
+  register rtx fp_reg;
   register tree fn_arg_types;
   register tree outer_scope;
-  register tree label;
+  register dw_die_ref old_die = lookup_decl_die (decl);
+  register int declaration = (current_function_decl != decl
+                             || context_die->die_tag == DW_TAG_structure_type
+                             || context_die->die_tag == DW_TAG_union_type);
 
-  if (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
-    {
-      add_AT_flag (subr_die, DW_AT_external, 1);
-    }
   if (origin != NULL)
     {
+      subr_die = new_die (DW_TAG_subprogram, context_die);
       add_abstract_origin_attribute (subr_die, origin);
     }
+  else if (old_die)
+    {
+      register unsigned file_index
+       = lookup_filename (DECL_SOURCE_FILE (decl));
+
+      assert (get_AT_flag (old_die, DW_AT_declaration) == 1);
+
+      /* If the definition comes from the same place as the declaration,
+        maybe use the old DIE.  We always want the DIE for this function
+        that has the *_pc attributes to be under comp_unit_die so the
+        debugger can find it.  For inlines, that is the concrete instance,
+        so we can use the old DIE here.  For non-inline methods, we want a
+        specification DIE at toplevel, so we need a new DIE.  For local
+        class methods, this does not apply.  */
+      if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die
+          || context_die == NULL)
+         && get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
+         && (get_AT_unsigned (old_die, DW_AT_decl_line)
+             == DECL_SOURCE_LINE (decl)))
+       {
+         subr_die = old_die;
+
+         /* Clear out the declaration attribute and the parm types.  */
+         remove_AT (subr_die, DW_AT_declaration);
+         remove_children (subr_die);
+       }
+      else
+       {
+         subr_die = new_die (DW_TAG_subprogram, context_die);
+         add_AT_die_ref (subr_die, DW_AT_specification, old_die);
+         if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
+           add_AT_unsigned (subr_die, DW_AT_decl_file, file_index);
+         if (get_AT_unsigned (old_die, DW_AT_decl_line)
+             != DECL_SOURCE_LINE (decl))
+           add_AT_unsigned
+             (subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
+       }
+    }
   else
     {
-      type = TREE_TYPE (decl);
+      register dw_die_ref scope_die;
+
+      if (DECL_CONTEXT (decl))
+       scope_die = scope_die_for (decl, context_die);
+      else
+       /* Don't put block extern declarations under comp_unit_die.  */
+       scope_die = context_die;
+
+      subr_die = new_die (DW_TAG_subprogram, scope_die);
+                        
+      if (TREE_PUBLIC (decl))
+       add_AT_flag (subr_die, DW_AT_external, 1);
+
       add_name_and_src_coords_attributes (subr_die, decl);
-      if (DECL_INLINE (decl))
+      if (debug_info_level > DINFO_LEVEL_TERSE)
        {
-         add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+         register tree type = TREE_TYPE (decl);
+
+         add_prototyped_attribute (subr_die, type);
+         add_type_attribute (subr_die, TREE_TYPE (type), 0, 0, context_die);
        }
-      add_prototyped_attribute (subr_die, type);
-      add_member_attribute (subr_die, DECL_CONTEXT (decl));
-      add_type_attribute (subr_die, TREE_TYPE (type), 0, 0, context_die);
+
       add_pure_or_virtual_attribute (subr_die, decl);
+      if (DECL_ARTIFICIAL (decl))
+       add_AT_flag (subr_die, DW_AT_artificial, 1);
+      if (TREE_PROTECTED (decl))
+       add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected);
+      else if (TREE_PRIVATE (decl))
+       add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private);
     }
-  if (DECL_ABSTRACT (decl))
+
+  if (declaration)
+    {
+      add_AT_flag (subr_die, DW_AT_declaration, 1);
+
+      /* The first time we see a member function, it is in the context of
+         the class to which it belongs.  We make sure of this by emitting
+         the class first.  The next time is the definition, which is
+         handled above.  The two may come from the same source text.  */
+      if (decl_class_context (decl))
+       equate_decl_number_to_die (decl, subr_die);
+    }
+  else if (DECL_ABSTRACT (decl))
     {
+      if (DECL_DEFER_OUTPUT (decl))
+       {
+         if (DECL_INLINE (decl))
+           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
+         else
+           add_AT_unsigned (subr_die, DW_AT_inline,
+                            DW_INL_declared_not_inlined);
+       }
+      else if (DECL_INLINE (decl))
+       add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+      else if (declaration)
+       /* Block extern declaration in an inline function.  */
+       add_AT_flag (subr_die, DW_AT_declaration, 1);
+      else
+       abort ();
+
       equate_decl_number_to_die (decl, subr_die);
     }
   else if (!DECL_EXTERNAL (decl))
     {
-      equate_decl_number_to_die (decl, subr_die);
-      add_AT_lbl_id (subr_die, DW_AT_low_pc, function_start_label (decl));
-      sprintf (label_id, FUNC_END_LABEL_FMT, current_funcdef_number);
+      if (origin == NULL_TREE)
+       equate_decl_number_to_die (decl, subr_die);
+
+      ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
+                                  current_funcdef_number);
+      add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
+      ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+                                  current_funcdef_number);
       add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
 
-#ifdef MIPS_DEBUGGING_INFO
+      add_pubname (decl, subr_die);
+      add_arange (decl, subr_die);
 
+#ifdef MIPS_DEBUGGING_INFO
       /* Add a reference to the FDE for this routine.  */
       add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
 #endif
 
-      /* Define the frame pointer location for this routine.  */
-      fp_reg = (frame_pointer_needed) ? FRAME_POINTER_REGNUM
-                                     : STACK_POINTER_REGNUM;
-      assert (fp_reg >= 0 && fp_reg <= 31);
-      fp_loc = new_loc_descr (DW_OP_breg0 + fp_reg, current_funcdef_frame_size);
-      add_AT_loc (subr_die, DW_AT_frame_base, fp_loc);
-
-#ifdef DWARF_GNU_EXTENSIONS
-      sprintf (label_id, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
-      add_AT_lbl_id (subr_die, DW_AT_body_begin, label_id);
-      sprintf (label_id, BODY_END_LABEL_FMT, current_funcdef_number);
-      add_AT_lbl_id (subr_die, DW_AT_body_end, label_id);
-#endif
+      /* Define the "frame base" location for this routine.  We use the
+         frame pointer or stack pointer registers, since the RTL for local
+         variables is relative to one of them.  */
+      fp_reg
+       = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
+      add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
 
+      if (current_function_needs_context)
+       add_AT_loc (subr_die, DW_AT_static_link,
+                   loc_descriptor (lookup_static_chain (decl)));
     }
 
   /* Now output descriptions of the arguments for this function. This gets
@@ -6148,14 +7350,15 @@ gen_subprogram_die (decl, context_die)
      FUNCTION_TYPE. If the chain of type nodes hanging off of this
      FUNCTION_TYPE node ends with a void_type_node then there should *not* be 
      an ellipsis at the end.  */
+  push_decl_scope (decl);
 
   /* In the case where we are describing a mere function declaration, all we
      need to do here (and all we *can* do here) is to describe the *types* of 
      its formal parameters.  */
-  if (DECL_INITIAL (decl) == NULL_TREE)
-    {
-      gen_formal_types_die (TREE_TYPE (decl), subr_die);
-    }
+  if (debug_info_level <= DINFO_LEVEL_TERSE)
+    ;
+  else if (declaration)
+    gen_formal_types_die (TREE_TYPE (decl), subr_die);
   else
     {
       /* Generate DIEs to represent all known formal parameters */
@@ -6165,21 +7368,15 @@ gen_subprogram_die (decl, context_die)
       /* When generating DIEs, generate the unspecified_parameters DIE
          instead if we come across the arg "__builtin_va_alist" */
       for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
-       {
-         if (TREE_CODE (parm) == PARM_DECL)
-           {
-             if (DECL_NAME (parm) &&
-                 !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
-                          "__builtin_va_alist"))
-               {
-                 gen_unspecified_parameters_die (parm, subr_die);
-               }
-             else
-               {
-                 gen_decl_die (parm, subr_die);
-               }
-           }
-       }
+       if (TREE_CODE (parm) == PARM_DECL)
+         {
+           if (DECL_NAME (parm) &&
+               !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
+                        "__builtin_va_alist"))
+             gen_unspecified_parameters_die (parm, subr_die);
+           else
+             gen_decl_die (parm, subr_die);
+         }
 
       /* Decide whether we need a unspecified_parameters DIE at the end.
          There are 2 more cases to do this for: 1) the ansi ... declaration - 
@@ -6188,62 +7385,57 @@ gen_subprogram_die (decl, context_die)
          definition).  This just means that we have no info about the
          parameters at all.  */
       fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
-      if (fn_arg_types)
+      if (fn_arg_types != NULL)
        {
          /* this is the prototyped case, check for ...  */
          if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
-           {
-             gen_unspecified_parameters_die (decl, subr_die);
-           }
-       }
-      else
-       {
-         /* this is unprotoyped, check for undefined (just declaration) */
-         if (!DECL_INITIAL (decl))
-           {
-             gen_unspecified_parameters_die (decl, subr_die);
-           }
+           gen_unspecified_parameters_die (decl, subr_die);
        }
+      else if (DECL_INITIAL (decl) == NULL_TREE)
+       gen_unspecified_parameters_die (decl, subr_die);
     }
 
   /* Output Dwarf info for all of the stuff within the body of the function
      (if it has one - it may be just a declaration).  */
   outer_scope = DECL_INITIAL (decl);
 
-  if (outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
-    {
-      /* Note that here, `outer_scope' is a pointer to the outermost BLOCK
-         node created to represent a function. This outermost BLOCK actually
-         represents the outermost binding contour for the function, i.e. the
-         contour in which the function's formal parameters and labels get
-         declared. Curiously, it appears that the front end doesn't actually
-         put the PARM_DECL nodes for the current function onto the BLOCK_VARS 
-         list for this outer scope.  (They are strung off of the
-         DECL_ARGUMENTS list for the function instead.) The BLOCK_VARS list
-         for the `outer_scope' does provide us with a list of the LABEL_DECL
-         nodes for the function however, and we output DWARF info for those
-         here. Just within the `outer_scope' there will be another BLOCK node
-         representing the function's outermost pair of curly braces.  We
-         musn't generate a lexical_block DIE for this outermost pair of curly
-         braces because that is not really an independent scope according to
-         ANSI C rules.  Rather, it is the same scope in which the parameters
-         were declared.  */
-      for (label = BLOCK_VARS (outer_scope);
-          label;
-          label = TREE_CHAIN (label))
+  /* Note that here, `outer_scope' is a pointer to the outermost BLOCK
+     node created to represent a function. This outermost BLOCK actually
+     represents the outermost binding contour for the function, i.e. the
+     contour in which the function's formal parameters and labels get
+     declared. Curiously, it appears that the front end doesn't actually
+     put the PARM_DECL nodes for the current function onto the BLOCK_VARS
+     list for this outer scope.  (They are strung off of the DECL_ARGUMENTS
+     list for the function instead.) The BLOCK_VARS list for the
+     `outer_scope' does provide us with a list of the LABEL_DECL nodes for
+     the function however, and we output DWARF info for those in
+     decls_for_scope.  Just within the `outer_scope' there will be a BLOCK
+     node representing the function's outermost pair of curly braces, and
+     any blocks used for the base and member initializers of a C++
+     constructor function.  */
+  if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
+    {
+      current_function_has_inlines = 0;
+      decls_for_scope (outer_scope, subr_die, 0);
+
+#if 0 && defined (MIPS_DEBUGGING_INFO)
+      if (current_function_has_inlines)
        {
-         gen_decl_die (label, subr_die);
+         add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1);
+         if (! comp_unit_has_inlines)
+           {
+             add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1);
+             comp_unit_has_inlines = 1;
+           }
        }
-
-      /* Note here that `BLOCK_SUBBLOCKS (outer_scope)' points to a list of
-         BLOCK nodes which is always only one element long. That one element
-         represents the outermost pair of curley braces for the function
-         body.  */
-      decls_for_scope (BLOCK_SUBBLOCKS (outer_scope), subr_die);
+#endif
     }
+
+  pop_decl_scope ();
 }
 
 /* Generate a DIE to represent a declared data object.  */
+
 static void
 gen_variable_die (decl, context_die)
      register tree decl;
@@ -6251,33 +7443,77 @@ gen_variable_die (decl, context_die)
 {
   register tree origin = decl_ultimate_origin (decl);
   register dw_die_ref var_die = new_die (DW_TAG_variable, context_die);
-  if (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
-    {
-      add_AT_flag (var_die, DW_AT_external, 1);
-    }
+
+  dw_die_ref old_die = lookup_decl_die (decl);
+  int declaration
+    = (DECL_EXTERNAL (decl)
+       || current_function_decl != decl_function_context (decl)
+       || context_die->die_tag == DW_TAG_structure_type
+       || context_die->die_tag == DW_TAG_union_type);
+
   if (origin != NULL)
-    {
-      add_abstract_origin_attribute (var_die, origin);
+    add_abstract_origin_attribute (var_die, origin);
+  /* Loop unrolling can create multiple blocks that refer to the same
+     static variable, so we must test for the DW_AT_declaration flag.  */
+  /* ??? Loop unrolling/reorder_blocks should perhaps be rewritten to
+     copy decls and set the DECL_ABSTRACT flag on them instead of
+     sharing them.  */
+  else if (old_die && TREE_STATIC (decl)
+          && get_AT_flag (old_die, DW_AT_declaration) == 1)
+    {
+      /* ??? This is an instantiation of a C++ class level static.  */
+      add_AT_die_ref (var_die, DW_AT_specification, old_die);
+      if (DECL_NAME (decl))
+       {
+         register unsigned file_index
+           = lookup_filename (DECL_SOURCE_FILE (decl));
+
+         if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
+           add_AT_unsigned (var_die, DW_AT_decl_file, file_index);
+
+         if (get_AT_unsigned (old_die, DW_AT_decl_line)
+             != DECL_SOURCE_LINE (decl))
+
+           add_AT_unsigned (var_die, DW_AT_decl_line,
+                            DECL_SOURCE_LINE (decl));
+       }
     }
   else
     {
       add_name_and_src_coords_attributes (var_die, decl);
-      add_member_attribute (var_die, DECL_CONTEXT (decl));
       add_type_attribute (var_die, TREE_TYPE (decl),
                          TREE_READONLY (decl),
                          TREE_THIS_VOLATILE (decl), context_die);
+
+      if (TREE_PUBLIC (decl))
+       add_AT_flag (var_die, DW_AT_external, 1);
+
+      if (DECL_ARTIFICIAL (decl))
+       add_AT_flag (var_die, DW_AT_artificial, 1);
+
+      if (TREE_PROTECTED (decl))
+       add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected);
+
+      else if (TREE_PRIVATE (decl))
+       add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private);
     }
-  if (DECL_ABSTRACT (decl))
+
+  if (declaration)
+    add_AT_flag (var_die, DW_AT_declaration, 1);
+  
+  if ((declaration && decl_class_context (decl)) || DECL_ABSTRACT (decl))
+    equate_decl_number_to_die (decl, var_die);
+
+  if (! declaration && ! DECL_ABSTRACT (decl))
     {
       equate_decl_number_to_die (decl, var_die);
-    }
-  else if (!DECL_EXTERNAL (decl))
-    {
       add_location_or_const_value_attribute (var_die, decl);
+      add_pubname (decl, var_die);
     }
 }
 
 /* Generate a DIE to represent a label identifier.  */
+
 static void
 gen_label_die (decl, context_die)
      register tree decl;
@@ -6287,18 +7523,15 @@ gen_label_die (decl, context_die)
   register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die);
   register rtx insn;
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
+  char label2[MAX_ARTIFICIAL_LABEL_BYTES];
+
   if (origin != NULL)
-    {
-      add_abstract_origin_attribute (lbl_die, origin);
-    }
+    add_abstract_origin_attribute (lbl_die, origin);
   else
-    {
-      add_name_and_src_coords_attributes (lbl_die, decl);
-    }
+    add_name_and_src_coords_attributes (lbl_die, decl);
+
   if (DECL_ABSTRACT (decl))
-    {
-      equate_decl_number_to_die (decl, lbl_die);
-    }
+    equate_decl_number_to_die (decl, lbl_die);
   else
     {
       insn = DECL_RTL (decl);
@@ -6310,66 +7543,83 @@ gen_label_die (decl, context_die)
             the user.  This really shouldn't be happening though, so catch
             it if it ever does happen.  */
          if (INSN_DELETED_P (insn))
-           {
-             abort ();         /* Should never happen.  */
-           }
-         sprintf (label, INSN_LABEL_FMT, current_funcdef_number,
-                  (unsigned) INSN_UID (insn));
+           abort ();
+
+         sprintf (label2, INSN_LABEL_FMT, current_funcdef_number);
+         ASM_GENERATE_INTERNAL_LABEL (label, label2,
+                                      (unsigned) INSN_UID (insn));
          add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
        }
     }
 }
 
 /* Generate a DIE for a lexical block.  */
+
 static void
-gen_lexical_block_die (stmt, context_die)
+gen_lexical_block_die (stmt, context_die, depth)
      register tree stmt;
      register dw_die_ref context_die;
+     int depth;
 {
   register dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die);
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  if (!BLOCK_ABSTRACT (stmt))
+
+  if (! BLOCK_ABSTRACT (stmt))
     {
-      sprintf (label, BLOCK_BEGIN_LABEL_FMT, next_block_number);
+      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+                                  next_block_number);
       add_AT_lbl_id (stmt_die, DW_AT_low_pc, label);
-      sprintf (label, BLOCK_END_LABEL_FMT, next_block_number);
+      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number);
       add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
     }
-  decls_for_scope (stmt, stmt_die);
+
+  push_decl_scope (stmt);
+  decls_for_scope (stmt, stmt_die, depth);
+  pop_decl_scope ();
 }
 
 /* Generate a DIE for an inlined subprogram.  */
+
 static void
-gen_inlined_subroutine_die (stmt, context_die)
+gen_inlined_subroutine_die (stmt, context_die, depth)
      register tree stmt;
      register dw_die_ref context_die;
+     int depth;
 {
-  register dw_die_ref subr_die = new_die (DW_TAG_inlined_subroutine,
-                                         context_die);
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  add_abstract_origin_attribute (subr_die, block_ultimate_origin (stmt));
-  if (!BLOCK_ABSTRACT (stmt))
+  if (! BLOCK_ABSTRACT (stmt))
     {
-      sprintf (label, BLOCK_BEGIN_LABEL_FMT, next_block_number);
+      register dw_die_ref subr_die
+       = new_die (DW_TAG_inlined_subroutine, context_die);
+      register tree decl = block_ultimate_origin (stmt);
+      char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+      add_abstract_origin_attribute (subr_die, decl);
+      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+                                  next_block_number);
       add_AT_lbl_id (subr_die, DW_AT_low_pc, label);
-      sprintf (label, BLOCK_END_LABEL_FMT, next_block_number);
+      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number);
       add_AT_lbl_id (subr_die, DW_AT_high_pc, label);
+      push_decl_scope (decl);
+      decls_for_scope (stmt, subr_die, depth);
+      pop_decl_scope ();
+      current_function_has_inlines = 1;
     }
-  decls_for_scope (stmt, subr_die);
 }
 
 /* Generate a DIE for a field in a record, or structure.  */
+
 static void
 gen_field_die (decl, context_die)
      register tree decl;
      register dw_die_ref context_die;
 {
   register dw_die_ref decl_die = new_die (DW_TAG_member, context_die);
+
   add_name_and_src_coords_attributes (decl_die, decl);
-  add_member_attribute (decl_die, DECL_CONTEXT (decl));
   add_type_attribute (decl_die, member_declared_type (decl),
                      TREE_READONLY (decl), TREE_THIS_VOLATILE (decl),
                      context_die);
+
   /* If this is a bit field...  */
   if (DECL_BIT_FIELD_TYPE (decl))
     {
@@ -6377,11 +7627,23 @@ gen_field_die (decl, context_die)
       add_bit_size_attribute (decl_die, decl);
       add_bit_offset_attribute (decl_die, decl);
     }
-  add_data_member_location_attribute (decl_die, decl);
+
+  if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE)
+    add_data_member_location_attribute (decl_die, decl);
+
+  if (DECL_ARTIFICIAL (decl))
+    add_AT_flag (decl_die, DW_AT_artificial, 1);
+
+  if (TREE_PROTECTED (decl))
+    add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected);
+
+  else if (TREE_PRIVATE (decl))
+    add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private);
 }
 
-/* Don't generate either pointer_type DIEs or reference_type DIEs.
-   Use modified type DIE's instead.
+#if 0
+/* Don't generate either pointer_type DIEs or reference_type DIEs here.
+   Use modified_type_die instead.
    We keep this code here just in case these types of DIEs may be needed to
    represent certain things in other languages (e.g. Pascal) someday.  */
 static void
@@ -6389,14 +7651,16 @@ gen_pointer_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref ptr_die = new_die (DW_TAG_pointer_type, context_die);
+  register dw_die_ref ptr_die
+    = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die));
+
   equate_type_number_to_die (type, ptr_die);
-  add_member_attribute (ptr_die, TYPE_CONTEXT (type));
   add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
 }
 
-/* Don't generate either pointer_type DIEs or reference_type DIEs.
-   Use modified type DIE's instead.
+/* Don't generate either pointer_type DIEs or reference_type DIEs here.
+   Use modified_type_die instead.
    We keep this code here just in case these types of DIEs may be needed to
    represent certain things in other languages (e.g. Pascal) someday.  */
 static void
@@ -6404,11 +7668,14 @@ gen_reference_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref ref_die = new_die (DW_TAG_reference_type, context_die);
+  register dw_die_ref ref_die
+    = new_die (DW_TAG_reference_type, scope_die_for (type, context_die));
+
   equate_type_number_to_die (type, ref_die);
-  add_member_attribute (ref_die, TYPE_CONTEXT (type));
   add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
+  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
 }
+#endif
 
 /* Generate a DIE for a pointer to a member type.  */
 static void
@@ -6416,36 +7683,29 @@ gen_ptr_to_mbr_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref ptr_die = new_die (DW_TAG_ptr_to_member_type,
-                                        context_die);
+  register dw_die_ref ptr_die
+    = new_die (DW_TAG_ptr_to_member_type, scope_die_for (type, context_die));
+
   equate_type_number_to_die (type, ptr_die);
-  add_member_attribute (ptr_die, TYPE_CONTEXT (type));
   add_AT_die_ref (ptr_die, DW_AT_containing_type,
-             lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
+                 lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
   add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
 }
 
 /* Generate the DIE for the compilation unit.  */
+
 static void
 gen_compile_unit_die (main_input_filename)
      register char *main_input_filename;
 {
   char producer[250];
-  char full_src_name[1024];
   char *wd = getpwd ();
 
   comp_unit_die = new_die (DW_TAG_compile_unit, NULL);
+  add_name_attribute (comp_unit_die, main_input_filename);
 
-  /* MIPS/SGI requires the full pathname of the input file.  */
-  if (main_input_filename[0] == '/')
-    {
-      add_name_attribute (comp_unit_die, main_input_filename);
-    }
-  else
-    {
-      sprintf (full_src_name, "%s/%s", wd, main_input_filename);
-      add_name_attribute (comp_unit_die, full_src_name);
-    }
+  if (wd != NULL)
+    add_AT_string (comp_unit_die, DW_AT_comp_dir, wd);
 
   sprintf (producer, "%s %s", language_string, version_string);
 
@@ -6456,74 +7716,81 @@ gen_compile_unit_die (main_input_filename)
      that the object file is stripped and has no debugging information.
      To get the MIPS/SGI debugger to believe that there is debugging
      information in the object file, we add a -g to the producer string.  */
-  if (write_symbols != NO_DEBUG)
-    {
-       strcpy (producer, " -g");
-    }
-
+  if (debug_info_level > DINFO_LEVEL_TERSE)
+    strcat (producer, " -g");
 #endif
 
   add_AT_string (comp_unit_die, DW_AT_producer, producer);
+
   if (strcmp (language_string, "GNU C++") == 0)
-    {
-      add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus);
-    }
+    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus);
+
   else if (strcmp (language_string, "GNU Ada") == 0)
-    {
-      add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83);
-    }
+    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83);
+
+  else if (strcmp (language_string, "GNU F77") == 0)
+    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Fortran77);
+
   else if (flag_traditional)
-    {
-      add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C);
-    }
+    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C);
+
   else
-    {
-      add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89);
-    }
-  add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, TEXT_BEGIN_LABEL);
-  add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, TEXT_END_LABEL);
-  if (wd)
-    {
-      add_AT_string (comp_unit_die, DW_AT_comp_dir, wd);
-    }
-  if (debug_info_level >= DINFO_LEVEL_NORMAL)
-    {
-      add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, LINE_SECTION);
-      if (debug_info_level >= DINFO_LEVEL_VERBOSE)
-       {
-         add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0);
-       }
-    }
+    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89);
+
+#if 0 /* unimplemented */
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0);
+#endif
 }
 
 /* Generate a DIE for a string type.  */
+
 static void
 gen_string_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register dw_die_ref type_die;
-  type_die = new_die (DW_TAG_string_type,
-                     scope_die_for_type (type, context_die));
-  add_member_attribute (type_die, TYPE_CONTEXT (type));
+  register dw_die_ref type_die
+    = new_die (DW_TAG_string_type, scope_die_for (type, context_die));
 
-  /* Fudge the string length attribute for now.  */
+  equate_type_number_to_die (type, type_die);
 
+  /* Fudge the string length attribute for now.  */
+  
   /* TODO: add string length info.
-     string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
+   string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
                              bound_representation (upper_bound, 0, 'u'); */
 }
 
+/* Generate the DIE for a base class.  */
+
+static void
+gen_inheritance_die (binfo, context_die)
+     register tree binfo;
+     register dw_die_ref context_die;
+{
+  dw_die_ref die = new_die (DW_TAG_inheritance, context_die);
+
+  add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die);
+  add_data_member_location_attribute (die, binfo);
+
+  if (TREE_VIA_VIRTUAL (binfo))
+    add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+  if (TREE_VIA_PUBLIC (binfo))
+    add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
+  else if (TREE_VIA_PROTECTED (binfo))
+    add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
+}
+
 /* Genearate a DIE for a class member.  */
+
 static void
 gen_member_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register tree normal_member;
-  register tree vec_base;
-  register tree first_func_member;
-  register tree func_member;
+  register tree member;
+
   /* If this is not an incomplete type, output descriptions of each of its
      members. Note that as we output the DIEs necessary to represent the
      members of this record or union type, we will also be trying to output
@@ -6537,126 +7804,161 @@ gen_member_die (type, context_die)
      to point to the TREE node representing the appropriate (containing)
      type.  */
 
-  /* First output info about the data members and type members.  */
-  for (normal_member = TYPE_FIELDS (type);
-       normal_member;
-       normal_member = TREE_CHAIN (normal_member))
+  /* First output info about the base classes.  */
+  if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
     {
-      gen_decl_die (normal_member, context_die);
+      register tree bases = TYPE_BINFO_BASETYPES (type);
+      register int n_bases = TREE_VEC_LENGTH (bases);
+      register int i;
+
+      for (i = 0; i < n_bases; i++)
+       gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die);
     }
 
-  /* Now output info about the function members (if any).  */
-  vec_base = TYPE_METHODS (type);
-  if (vec_base)
-    {
-      first_func_member = TREE_VEC_ELT (vec_base, 0);
-      /* This isn't documented, but the first element of the vector of member 
-         functions can be NULL in cases where the class type in question
-         didn't have either a constructor or a destructor declared for it.
-         We have to make allowances for that here.  */
-      if (first_func_member == NULL)
-       {
-         first_func_member = TREE_VEC_ELT (vec_base, 1);
-       }
+  /* Now output info about the data members and type members.  */
+  for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
+    gen_decl_die (member, context_die);
 
-      for (func_member = first_func_member;
-          func_member;
-          func_member = TREE_CHAIN (func_member))
-       {
-         gen_decl_die (func_member, context_die);
-       }
-    }
+  /* Now output info about the function members (if any).  */
+  for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
+    gen_decl_die (member, context_die);
 }
 
 /* Generate a DIE for a structure or union type.  */
+
 static void
-gen_struct_or_union_type_die (type, is_complete, context_die)
+gen_struct_or_union_type_die (type, context_die)
      register tree type;
-     register unsigned is_complete;
      register dw_die_ref context_die;
 {
-  register dw_die_ref type_die;
-  type_die = lookup_type_die (type);
-  if (type_die == NULL)
+  register dw_die_ref type_die = lookup_type_die (type);
+  register dw_die_ref scope_die = 0;
+  register int nested = 0;
+
+  if (type_die && ! TYPE_SIZE (type))
+    return;
+
+  if (TYPE_CONTEXT (type) != NULL_TREE
+      && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't')
+    nested = 1;
+
+  scope_die = scope_die_for (type, context_die);
+
+  if (! type_die || (nested && scope_die == comp_unit_die))
+    /* First occurrence of type or toplevel definition of nested class.  */
     {
+      register dw_die_ref old_die = type_die;
+
       type_die = new_die (TREE_CODE (type) == RECORD_TYPE
                          ? DW_TAG_structure_type : DW_TAG_union_type,
-                         scope_die_for_type (type, context_die));
+                         scope_die);
       equate_type_number_to_die (type, type_die);
       add_name_attribute (type_die, type_tag (type));
-      add_member_attribute (type_die, TYPE_CONTEXT (type));
+      if (old_die)
+       add_AT_die_ref (type_die, DW_AT_specification, old_die);
     }
+  else
+    remove_AT (type_die, DW_AT_declaration);
 
+  /* If we're not in the right context to be defining this type, defer to
+     avoid tricky recursion.  */
+  if (TYPE_SIZE (type) && decl_scope_depth > 0 && scope_die == comp_unit_die)
+    {
+      add_AT_flag (type_die, DW_AT_declaration, 1);
+      pend_type (type);
+    }
   /* If this type has been completed, then give it a byte_size attribute and
      then give a list of members.  */
-  if (is_complete)
+  else if (TYPE_SIZE (type))
     {
       /* Prevent infinite recursion in cases where the type of some member of 
          this type is expressed in terms of this type itself.  */
       TREE_ASM_WRITTEN (type) = 1;
-      if (TYPE_SIZE (type))
+      add_byte_size_attribute (type_die, type);
+      if (type_tag (type))
+       add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+
+      push_decl_scope (type);
+      gen_member_die (type, type_die);
+      pop_decl_scope ();
+
+      /* GNU extension: Record what type our vtable lives in.  */
+      if (TYPE_VFIELD (type))
        {
-         add_byte_size_attribute (type_die, type);
-         gen_member_die (type, type_die);
+         tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type));
+
+         gen_type_die (vtype, context_die);
+         add_AT_die_ref (type_die, DW_AT_containing_type,
+                         lookup_type_die (vtype));
        }
     }
+  else
+    add_AT_flag (type_die, DW_AT_declaration, 1);
 }
 
 /* Generate a DIE for a subroutine _type_.  */
+
 static void
 gen_subroutine_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
   register tree return_type = TREE_TYPE (type);
-  register dw_die_ref subr_die = new_die (DW_TAG_subroutine_type, context_die);
+  register dw_die_ref subr_die
+    = new_die (DW_TAG_subroutine_type, scope_die_for (type, context_die));
+
   equate_type_number_to_die (type, subr_die);
   add_prototyped_attribute (subr_die, type);
-  add_member_attribute (subr_die, TYPE_CONTEXT (type));
   add_type_attribute (subr_die, return_type, 0, 0, context_die);
-  gen_formal_types_die (type, context_die);
+  gen_formal_types_die (type, subr_die);
 }
 
 /* Generate a DIE for a type definition */
+
 static void
 gen_typedef_die (decl, context_die)
      register tree decl;
      register dw_die_ref context_die;
 {
-  register tree origin = decl_ultimate_origin (decl);
   register dw_die_ref type_die;
-  type_die = new_die (DW_TAG_typedef,
-                     scope_die_for_type (decl, context_die));
+  register tree origin;
+
+  if (TREE_ASM_WRITTEN (decl))
+    return;
+  TREE_ASM_WRITTEN (decl) = 1;
+
+  type_die = new_die (DW_TAG_typedef, scope_die_for (decl, context_die));
+  origin = decl_ultimate_origin (decl);
   if (origin != NULL)
-    {
-      add_abstract_origin_attribute (type_die, origin);
-    }
+    add_abstract_origin_attribute (type_die, origin);
   else
     {
+      register tree type;
       add_name_and_src_coords_attributes (type_die, decl);
-      add_member_attribute (type_die, DECL_CONTEXT (decl));
-      add_type_attribute (type_die, TREE_TYPE (decl),
-                         TREE_READONLY (decl),
-                         TREE_THIS_VOLATILE (decl),
-                         context_die);
+      if (DECL_ORIGINAL_TYPE (decl))
+       {
+         type = DECL_ORIGINAL_TYPE (decl);
+         equate_type_number_to_die (TREE_TYPE (decl), type_die);
+       }
+      else
+       type = TREE_TYPE (decl);
+      add_type_attribute (type_die, type, TREE_READONLY (decl),
+                         TREE_THIS_VOLATILE (decl), context_die);
     }
+
   if (DECL_ABSTRACT (decl))
-    {
-      equate_decl_number_to_die (decl, type_die);
-    }
+    equate_decl_number_to_die (decl, type_die);
 }
 
 /* Generate a type description DIE.  */
+
 static void
 gen_type_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  register unsigned is_complete;
-  if (type == 0 || type == error_mark_node)
-    {
-      return;
-    }
+  if (type == NULL_TREE || type == error_mark_node)
+    return;
 
   /* We are going to output a DIE to represent the unqualified version of of
      this type (i.e. without any const or volatile qualifiers) so get the
@@ -6664,7 +7966,13 @@ gen_type_die (type, context_die)
   type = type_main_variant (type);
 
   if (TREE_ASM_WRITTEN (type))
-    {
+    return;
+
+  if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+      && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+    { 
+      TREE_ASM_WRITTEN (type) = 1;
+      gen_decl_die (TYPE_NAME (type), context_die);
       return;
     }
 
@@ -6681,11 +7989,13 @@ gen_type_die (type, context_die)
       break;
 
     case OFFSET_TYPE:
-      /* This code is used for C++ pointer-to-data-member types.  */
-      /* Output a description of the relevant class type.  */
+      /* This code is used for C++ pointer-to-data-member types. 
+        Output a description of the relevant class type.  */
       gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die);
+
       /* Output a description of the type of the object pointed to.  */
       gen_type_die (TREE_TYPE (type), context_die);
+
       /* Now output a DIE to represent this pointer-to-data-member type
          itself.  */
       gen_ptr_to_mbr_type_die (type, context_die);
@@ -6720,53 +8030,43 @@ gen_type_die (type, context_die)
          gen_string_type_die (type, context_die);
        }
       else
-       {
-         gen_array_type_die (type, context_die);
-       }
+       gen_array_type_die (type, context_die);
       break;
 
     case ENUMERAL_TYPE:
     case RECORD_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      /* For a non-file-scope tagged type, we can always go ahead and output
-         a Dwarf description of this type right now, even if the type in
-         question is still incomplete, because if this local type *was* ever
-         completed anywhere within its scope, that complete definition would
-         already have been attached to this RECORD_TYPE, UNION_TYPE,
-         QUAL_UNION_TYPE or ENUMERAL_TYPE node by the time we reach this
-         point.  That's true because of the way the front-end does its
-         processing of file-scope declarations (of functions and class types) 
-         within which other types might be nested.  The C and C++ front-ends
-         always gobble up such "local scope" things en-mass before they try
-         to output *any* debugging information for any of the stuff contained 
-         inside them and thus, we get the benefit here of what is (in effect) 
-         a pre-resolution of forward references to tagged types in local
-         scopes. Note however that for file-scope tagged types we cannot
-         assume that such pre-resolution of forward references has taken
-         place. A given file-scope tagged type may appear to be incomplete
-         when we reach this point, but it may yet be given a full definition
-         (at file-scope) later on during compilation.  In order to avoid
-         generating a premature (and possibly incorrect) set of Dwarf DIEs
-         for such (as yet incomplete) file-scope tagged types, we generate
-         nothing at all for as-yet incomplete file-scope tagged types here
-         unless we are making our special "finalization" pass for file-scope
-         things at the very end of compilation.  At that time, we will
-         certainly know as much about each file-scope tagged type as we are
-         ever going to know, so at that point in time, we can safely generate 
-         correct Dwarf descriptions for these file-scope tagged types.  */
-      is_complete = TYPE_SIZE (type) != 0
-       || TYPE_CONTEXT (type) != NULL
-       || finalizing;
-      if (TREE_CODE (type) == ENUMERAL_TYPE)
-       {
-         gen_enumeration_type_die (type, is_complete, context_die);
-       }
-      else
+      /* If this is a nested type whose containing class hasn't been
+        written out yet, writing it out will cover this one, too.  */
+      if (TYPE_CONTEXT (type)
+         && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
+         && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
        {
-         gen_struct_or_union_type_die (type, is_complete, context_die);
+         gen_type_die (TYPE_CONTEXT (type), context_die);
+
+         if (TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+           return;
+
+         /* If that failed, attach ourselves to the stub.  */
+         push_decl_scope (TYPE_CONTEXT (type));
+         context_die = lookup_type_die (TYPE_CONTEXT (type));
        }
-      break;
+
+      if (TREE_CODE (type) == ENUMERAL_TYPE)
+       gen_enumeration_type_die (type, context_die);
+      else
+       gen_struct_or_union_type_die (type, context_die);
+
+      if (TYPE_CONTEXT (type)
+         && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
+         && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+       pop_decl_scope ();
+
+      /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
+        it up if it is ever completed.  gen_*_type_die will set it for us
+        when appropriate.  */
+      return;
 
     case VOID_TYPE:
     case INTEGER_TYPE:
@@ -6789,15 +8089,14 @@ gen_type_die (type, context_die)
 }
 
 /* Generate a DIE for a tagged type instantiation.  */
+
 static void
 gen_tagged_type_instantiation_die (type, context_die)
      register tree type;
      register dw_die_ref context_die;
 {
-  if (type == 0 || type == error_mark_node)
-    {
-      return;
-    }
+  if (type == NULL_TREE || type == error_mark_node)
+    return;
 
   /* We are going to output a DIE to represent the unqualified version of of
      this type (i.e. without any const or volatile qualifiers) so make sure
@@ -6825,16 +8124,18 @@ gen_tagged_type_instantiation_die (type, context_die)
       break;
 
     default:
-      abort ();                        /* Should never happen.  */
+      abort ();
     }
 }
 
 /* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the
    things which are local to the given block.  */
+
 static void
-gen_block_die (stmt, context_die)
+gen_block_die (stmt, context_die, depth)
      register tree stmt;
      register dw_die_ref context_die;
+     int depth;
 {
   register int must_output_die = 0;
   register tree origin;
@@ -6843,10 +8144,8 @@ gen_block_die (stmt, context_die)
 
   /* Ignore blocks never really used to make RTL.  */
 
-  if (!stmt || !TREE_USED (stmt))
-    {
-      return;
-    }
+  if (stmt == NULL_TREE || !TREE_USED (stmt))
+    return;
 
   /* Determine the "ultimate origin" of this block.  This block may be an
      inlined instance of an inlined instance of inline function, so we have
@@ -6859,11 +8158,9 @@ gen_block_die (stmt, context_die)
   /* Determine if we need to output any Dwarf DIEs at all to represent this
      block.  */
   if (origin_code == FUNCTION_DECL)
-    {
-      /* The outer scopes for inlinings *must* always be represented.  We
-         generate DW_TAG_inlined_subroutine DIEs for them.  (See below.) */
-      must_output_die = 1;
-    }
+    /* The outer scopes for inlinings *must* always be represented.  We
+       generate DW_TAG_inlined_subroutine DIEs for them.  (See below.) */
+    must_output_die = 1;
   else
     {
       /* In the case where the current block represents an inlining of the
@@ -6874,31 +8171,25 @@ gen_block_die (stmt, context_die)
          rules.  So we check here to make sure that this block does not
          represent a "body block inlining" before trying to set the
          `must_output_die' flag.  */
-      if (origin == NULL || !is_body_block (origin))
+      if (! is_body_block (origin ? origin : stmt))
        {
          /* Determine if this block directly contains any "significant"
             local declarations which we will need to output DIEs for.  */
          if (debug_info_level > DINFO_LEVEL_TERSE)
-           {
-             /* We are not in terse mode so *any* local declaration counts
-                as being a "significant" one.  */
-             must_output_die = (BLOCK_VARS (stmt) != NULL);
-           }
+           /* We are not in terse mode so *any* local declaration counts
+              as being a "significant" one.  */
+           must_output_die = (BLOCK_VARS (stmt) != NULL);
          else
-           {
-             /* We are in terse mode, so only local (nested) function
-                definitions count as "significant" local declarations.  */
-             for (decl = BLOCK_VARS (stmt);
-                  decl != NULL; decl = TREE_CHAIN (decl))
+           /* We are in terse mode, so only local (nested) function
+              definitions count as "significant" local declarations.  */
+           for (decl = BLOCK_VARS (stmt);
+                decl != NULL; decl = TREE_CHAIN (decl))
+             if (TREE_CODE (decl) == FUNCTION_DECL
+                 && DECL_INITIAL (decl))
                {
-                 if (TREE_CODE (decl) == FUNCTION_DECL
-                     && DECL_INITIAL (decl))
-                   {
-                     must_output_die = 1;
-                     break;
-                   }
+                 must_output_die = 1;
+                 break;
                }
-           }
        }
     }
 
@@ -6912,44 +8203,56 @@ gen_block_die (stmt, context_die)
   if (must_output_die)
     {
       if (origin_code == FUNCTION_DECL)
-       {
-         gen_inlined_subroutine_die (stmt, context_die);
-       }
+       gen_inlined_subroutine_die (stmt, context_die, depth);
       else
-       {
-         gen_lexical_block_die (stmt, context_die);
-       }
+       gen_lexical_block_die (stmt, context_die, depth);
     }
   else
-    decls_for_scope (stmt, context_die);
+    decls_for_scope (stmt, context_die, depth);
 }
 
 /* Generate all of the decls declared within a given scope and (recursively)
    all of it's sub-blocks.  */
+
 static void
-decls_for_scope (stmt, context_die)
+decls_for_scope (stmt, context_die, depth)
      register tree stmt;
      register dw_die_ref context_die;
+     int depth;
 {
   register tree decl;
   register tree subblocks;
+
   /* Ignore blocks never really used to make RTL.  */
-  if (!stmt || !TREE_USED (stmt))
-    {
-      return;
-    }
-  if (!BLOCK_ABSTRACT (stmt))
-    {
-      next_block_number++;
-    }
+  if (stmt == NULL_TREE || ! TREE_USED (stmt))
+    return;
 
-  /* Output the DIEs to represent all of the data objects, functions,
-     typedefs, and tagged types declared directly within this block but not
-     within any nested sub-blocks.  */
+  if (!BLOCK_ABSTRACT (stmt) && depth > 0)
+    next_block_number++;
+
+  /* Output the DIEs to represent all of the data objects and typedefs
+     declared directly within this block but not within any nested
+     sub-blocks.  Also, nested function and tag DIEs have been
+     generated with a parent of NULL; fix that up now.  */
   for (decl = BLOCK_VARS (stmt);
        decl != NULL; decl = TREE_CHAIN (decl))
     {
-      gen_decl_die (decl, context_die);
+      register dw_die_ref die;
+
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       die = lookup_decl_die (decl);
+      else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
+       die = lookup_type_die (TREE_TYPE (decl));
+      else
+       die = NULL;
+
+      if (die != NULL && die->die_parent == NULL)
+       {
+         add_child_die (context_die, die);
+         --limbo_die_count;
+       }
+      else
+       gen_decl_die (decl, context_die);
     }
 
   /* Output the DIEs to represent all sub-blocks (and the items declared
@@ -6957,27 +8260,45 @@ decls_for_scope (stmt, context_die)
   for (subblocks = BLOCK_SUBBLOCKS (stmt);
        subblocks != NULL;
        subblocks = BLOCK_CHAIN (subblocks))
-    {
-      gen_block_die (subblocks, context_die);
-    }
+    gen_block_die (subblocks, context_die, depth + 1);
+}
+
+/* Is this a typedef we can avoid emitting?  */
+
+static inline int
+is_redundant_typedef (decl)
+     register tree decl;
+{
+  if (TYPE_DECL_IS_STUB (decl))
+    return 1;
+
+  if (DECL_ARTIFICIAL (decl)
+      && DECL_CONTEXT (decl)
+      && is_tagged_type (DECL_CONTEXT (decl))
+      && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
+      && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
+    /* Also ignore the artificial member typedef for the class name.  */
+    return 1;
+
+  return 0;
 }
 
 /* Generate Dwarf debug information for a decl described by DECL.  */
+
 static void
 gen_decl_die (decl, context_die)
      register tree decl;
      register dw_die_ref context_die;
 {
   register tree origin;
+
   /* Make a note of the decl node we are going to be working on.  We may need 
      to give the user the source coordinates of where it appeared in case we
      notice (later on) that something about it looks screwy.  */
   dwarf_last_decl = decl;
 
   if (TREE_CODE (decl) == ERROR_MARK)
-    {
-      return;
-    }
+    return;
 
   /* If this ..._DECL node is marked to be ignored, then ignore it. But don't 
      ignore a function definition, since that would screw up our count of
@@ -6985,11 +8306,8 @@ gen_decl_die (decl, context_die)
      reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for
      subsequent blocks).  */
   if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_DECL)
-    {
-      return;
-    }
+    return;
 
-  push_decl_scope (DECL_CONTEXT (decl));
   switch (TREE_CODE (decl))
     {
     case CONST_DECL:
@@ -6998,15 +8316,27 @@ gen_decl_die (decl, context_die)
       break;
 
     case FUNCTION_DECL:
-      /* If we are in terse mode, don't output any DIEs to represent mere
-         function declarations.  */
-      if (DECL_INITIAL (decl) == NULL_TREE)
+      /* Don't output any DIEs to represent mere function declarations,
+        unless they are class members or explicit block externs.  */
+      if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE
+         && (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl)))
+       break;
+
+      if (debug_info_level > DINFO_LEVEL_TERSE)
        {
-         break;
+         /* Before we describe the FUNCTION_DECL itself, make sure that we
+            have described its return type.  */
+         gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
+
+         /* And its containing type.  */
+         origin = decl_class_context (decl);
+         if (origin != NULL_TREE)
+           gen_type_die (origin, context_die);
+
+         /* And its virtual context.  */
+         if (DECL_VINDEX (decl) != NULL_TREE)
+           gen_type_die (DECL_CONTEXT (decl), context_die);
        }
-      /* Before we describe the FUNCTION_DECL itself, make sure that we have
-         described its return type.  */
-      gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
 
       /* Now output a DIE to represent the function itself.  */
       gen_subprogram_die (decl, context_die);
@@ -7014,85 +8344,66 @@ gen_decl_die (decl, context_die)
 
     case TYPE_DECL:
       /* If we are in terse mode, don't generate any DIEs to represent any
-         actual typedefs.  Note that even when we are in terse mode, we must
-         still output DIEs to represent those tagged types which are used
-         (directly or indirectly) in the specification of either a return
-         type or a formal parameter type of some function.  */
+         actual typedefs.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
-       {
-         if (DECL_NAME (decl) != NULL
-             || !TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)))
-           {
-             break;
-           }
-       }
+       break;
 
-      /* In the special case of a null-named TYPE_DECL node (representing the 
-         declaration of some type tag), if the given TYPE_DECL is marked as
+      /* In the special case of a TYPE_DECL node representing the 
+         declaration of some type tag, if the given TYPE_DECL is marked as
          having been instantiated from some other (original) TYPE_DECL node
          (e.g. one which was generated within the original definition of an
          inline function) we have to generate a special (abbreviated)
          DW_TAG_structure_type, DW_TAG_union_type, or DW_TAG_enumeration-type 
          DIE here.  */
-      if (!DECL_NAME (decl) && DECL_ABSTRACT_ORIGIN (decl))
+      if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE)
        {
          gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
          break;
        }
-      gen_type_die (TREE_TYPE (decl), context_die);
 
-      /* Note that unlike the gcc front end (which generates a NULL named
-         TYPE_DECL node for each complete tagged type, each array type, and
-         each function type node created) the g++ front end generates a
-         _named_ TYPE_DECL node for each tagged type node created.
-         Unfortunately, these g++ TYPE_DECL nodes cause us to output many
-         superfluous and unnecessary DW_TAG_typedef DIEs here.  When g++ is
-         fixed to stop generating these superfluous named TYPE_DECL nodes,
-         the superfluous DW_TAG_typedef DIEs will likewise cease.  */
-      if (DECL_NAME (decl))
-       {
-         /* Output a DIE to represent the typedef itself.  */
-         gen_typedef_die (decl, context_die);
-       }
+      if (is_redundant_typedef (decl))
+       gen_type_die (TREE_TYPE (decl), context_die);
+      else
+       /* Output a DIE to represent the typedef itself.  */
+       gen_typedef_die (decl, context_die);
       break;
 
     case LABEL_DECL:
       if (debug_info_level >= DINFO_LEVEL_NORMAL)
-       {
-         gen_label_die (decl, context_die);
-       }
+       gen_label_die (decl, context_die);
       break;
 
     case VAR_DECL:
       /* If we are in terse mode, don't generate any DIEs to represent any
          variable declarations or definitions.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
-       {
-         break;
-       }
+       break;
 
       /* Output any DIEs that are needed to specify the type of this data
          object.  */
       gen_type_die (TREE_TYPE (decl), context_die);
 
+      /* And its containing type.  */
+      origin = decl_class_context (decl);
+      if (origin != NULL_TREE)
+       gen_type_die (origin, context_die);
+
       /* Now output the DIE to represent the data object itself.  This gets
          complicated because of the possibility that the VAR_DECL really
          represents an inlined instance of a formal parameter for an inline
          function.  */
       origin = decl_ultimate_origin (decl);
-      if (origin != NULL && TREE_CODE (origin) == PARM_DECL)
-       {
-         gen_formal_parameter_die (decl, context_die);
-       }
+      if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
+       gen_formal_parameter_die (decl, context_die);
       else
-       {
-         gen_variable_die (decl, context_die);
-       }
+       gen_variable_die (decl, context_die);
       break;
 
     case FIELD_DECL:
-      /* Ignore the nameless fields that are used to skip bits.  */
-      if (DECL_NAME (decl) != 0)
+      /* Ignore the nameless fields that are used to skip bits, but
+        handle C++ anonymous unions.  */
+      if (DECL_NAME (decl) != NULL_TREE
+         || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE)
        {
          gen_type_die (member_declared_type (decl), context_die);
          gen_field_die (decl, context_die);
@@ -7107,19 +8418,18 @@ gen_decl_die (decl, context_die)
     default:
       abort ();
     }
-  pop_decl_scope ();
 }
 \f
-/***************** Debug Information Generation Hooks ***********************/
+/* Write the debugging output for DECL.  */
+
 void
-dwarfout_file_scope_decl (decl, set_finalizing)
+dwarf2out_decl (decl)
      register tree decl;
-     register int set_finalizing;
 {
+  register dw_die_ref context_die = comp_unit_die;
+
   if (TREE_CODE (decl) == ERROR_MARK)
-    {
-      return;
-    }
+    return;
 
   /* If this ..._DECL node is marked to be ignored, then ignore it.  We gotta 
      hope that the node in question doesn't represent a function definition.
@@ -7132,9 +8442,8 @@ dwarfout_file_scope_decl (decl, set_finalizing)
     {
       if (TREE_CODE (decl) == FUNCTION_DECL
          && DECL_INITIAL (decl) != NULL)
-       {
-         abort ();
-       }
+       abort ();
+
       return;
     }
 
@@ -7145,9 +8454,7 @@ dwarfout_file_scope_decl (decl, set_finalizing)
          builtin function.  Explicit programmer-supplied declarations of
          these same functions should NOT be ignored however.  */
       if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl))
-       {
-         return;
-       }
+       return;
 
       /* What we would really like to do here is to filter out all mere
          file-scope declarations of file-scope functions which are never
@@ -7170,14 +8477,19 @@ dwarfout_file_scope_decl (decl, set_finalizing)
          out-of-lines instances of such things (despite the fact that they
          *are* definitions).  The important point is that the C front-end
          marks these "extern inline" functions as DECL_EXTERNAL, but we need
-         to generate DWARf for them anyway. Note that the C++ front-end also
+         to generate DWARF for them anyway. Note that the C++ front-end also
          plays some similar games for inline function definitions appearing
          within include files which also contain 
         `#pragma interface' pragmas.  */
       if (DECL_INITIAL (decl) == NULL_TREE)
-       {
-         return;
-       }
+       return;
+
+      /* Ignore nested functions, since they will be written in decl_for_scope.
+        ??? There was an old comment here about methods, which now need to
+        be handled.  */
+      if (decl_function_context (decl))
+       return;
+
       break;
 
     case VAR_DECL:
@@ -7190,127 +8502,112 @@ dwarfout_file_scope_decl (decl, set_finalizing)
          would screw-up the debugger's name lookup mechanism and cause it to
          miss things which really ought to be in scope at a given point.  */
       if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
-       {
-         return;
-       }
+       return;
 
       /* If we are in terse mode, don't generate any DIEs to represent any
          variable declarations or definitions.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
-       {
-         return;
-       }
+       return;
       break;
 
     case TYPE_DECL:
       /* Don't bother trying to generate any DIEs to represent any of the
-         normal built-in types for the language we are compiling, except in
-         cases where the types in question are *not* DWARF fundamental types. 
-         We make an exception in the case of non-fundamental types for the
-         sake of objective C (and perhaps C++) because the GNU front-ends for 
-         these languages may in fact create certain "built-in" types which
-         are (for example) RECORD_TYPEs.  In such cases, we really need to
-         output these (non-fundamental) types because other DIEs may contain
-         references to them.  */
-      if (DECL_SOURCE_LINE (decl) == 0
-         && is_base_type (TREE_TYPE (decl)))
+         normal built-in types for the language we are compiling.  */
+      if (DECL_SOURCE_LINE (decl) == 0)
        {
+         /* OK, we need to generate one for `bool' so GDB knows what type
+             comparisons have.  */
+         if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
+              == DW_LANG_C_plus_plus)
+             && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE)
+           modified_type_die (TREE_TYPE (decl), 0, 0, NULL);
+
          return;
        }
 
-      /* If we are in terse mode, don't generate any DIEs to represent any
-         actual typedefs.  Note that even when we are in terse mode, we must
-         still output DIEs to represent those tagged types which are used
-         (directly or indirectly) in the specification of either a return
-         type or a formal parameter type of some function.  */
+      /* If we are in terse mode, don't generate any DIEs for types.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
-       {
-         if (DECL_NAME (decl) != NULL
-             || !TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)))
-           {
-             return;
-           }
-       }
+       return;
+
+      /* If we're a function-scope tag, initially use a parent of NULL;
+        this will be fixed up in decls_for_scope.  */
+      if (decl_function_context (decl))
+       return;
+
       break;
 
     default:
       return;
     }
 
-  finalizing = set_finalizing;
-  gen_decl_die (decl, comp_unit_die);
-
-  if (TREE_CODE (decl) == FUNCTION_DECL
-      && DECL_INITIAL (decl) != NULL)
-    {
-      current_funcdef_number++;
-    }
+  gen_decl_die (decl, context_die);
+  output_pending_types_for_scope (comp_unit_die);
 
+  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl) != NULL_TREE)
+    current_funcdef_number++;
 }
 
 /* Output a marker (i.e. a label) for the beginning of the generated code for
    a lexical block.  */
+
 void
-dwarfout_begin_block (blocknum)
+dwarf2out_begin_block (blocknum)
      register unsigned blocknum;
 {
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-
   function_section (current_function_decl);
-  sprintf (label, BLOCK_BEGIN_LABEL_FMT, blocknum);
-  ASM_OUTPUT_LABEL (asm_out_file, label);
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
 }
 
 /* Output a marker (i.e. a label) for the end of the generated code for a
    lexical block.  */
+
 void
-dwarfout_end_block (blocknum)
+dwarf2out_end_block (blocknum)
      register unsigned blocknum;
 {
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-
   function_section (current_function_decl);
-  sprintf (label, BLOCK_END_LABEL_FMT, blocknum);
-  ASM_OUTPUT_LABEL (asm_out_file, label);
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
 }
 
 /* Output a marker (i.e. a label) at a point in the assembly code which
    corresponds to a given source level label.  */
+
 void
-dwarfout_label (insn)
+dwarf2out_label (insn)
      register rtx insn;
 {
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
   if (debug_info_level >= DINFO_LEVEL_NORMAL)
     {
       function_section (current_function_decl);
-      sprintf (label, INSN_LABEL_FMT, current_funcdef_number,
-              (unsigned) INSN_UID (insn));
-      ASM_OUTPUT_LABEL (asm_out_file, label);
+      sprintf (label, INSN_LABEL_FMT, current_funcdef_number);
+      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label,
+                                (unsigned) INSN_UID (insn));
     }
 }
 
-/* Output a marker (i.e. a label) for the point in the generated code where
-   the real body of the function begins (after parameters have been moved to
-   their home locations).  */
+/* Output a marker (i.e. a label) for the beginning of a function, before
+   the prologue.  */
+
 void
-dwarfout_begin_function ()
+dwarf2out_begin_prologue ()
 {
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  register long int offset;
   register dw_fde_ref fde;
-  register dw_cfi_ref cfi;
 
   function_section (current_function_decl);
-  sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
+                              current_funcdef_number);
   ASM_OUTPUT_LABEL (asm_out_file, label);
 
   /* Expand the fde table if necessary.  */
   if (fde_table_in_use == fde_table_allocated)
     {
       fde_table_allocated += FDE_TABLE_INCREMENT;
-      fde_table = (dw_fde_ref) xrealloc (fde_table,
-              fde_table_allocated * sizeof (dw_fde_node));
+      fde_table
+       = (dw_fde_ref) xrealloc (fde_table,
+                                fde_table_allocated * sizeof (dw_fde_node));
     }
 
   /* Record the FDE associated with this function.  */
@@ -7318,116 +8615,32 @@ dwarfout_begin_function ()
 
   /* Add the new FDE at the end of the fde_table.  */
   fde = &fde_table[fde_table_in_use++];
-  fde->dw_fde_begin = xstrdup (function_start_label (current_function_decl));
-  fde->dw_fde_end_prolog = xstrdup (label);
-  fde->dw_fde_begin_epilogue = NULL;
+  fde->dw_fde_begin = xstrdup (label);
+  fde->dw_fde_current_label = NULL;
   fde->dw_fde_end = NULL;
   fde->dw_fde_cfi = NULL;
-
-#ifdef MIPS_DEBUGGING_INFO
-
-  /* On entry, the Call Frame Address is in the stack pointer register.  */
-  cfi = new_cfi ();
-  cfi->dw_cfi_opc = DW_CFA_def_cfa;
-  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = STACK_POINTER_REGNUM;
-  cfi->dw_cfi_oprnd2.dw_cfi_offset = 0;
-  add_cfi (&fde->dw_fde_cfi, cfi);
-
-  /* Set the location counter to the end of the function prolog.  */
-  cfi = new_cfi ();
-  cfi->dw_cfi_opc = DW_CFA_advance_loc4;
-  cfi->dw_cfi_oprnd1.dw_cfi_addr = xstrdup (label);
-  add_cfi (&fde->dw_fde_cfi, cfi);
-
-  /* Define the CFA as either an explicit frame pointer register,
-     or an offset from the stack pointer.  */
-  cfi = new_cfi ();
-  cfi->dw_cfi_opc = DW_CFA_def_cfa;
-  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = (frame_pointer_needed)
-                                      ? FRAME_POINTER_REGNUM
-                                      : STACK_POINTER_REGNUM;
-  offset = current_frame_info.total_size;
-  cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
-  add_cfi (&fde->dw_fde_cfi, cfi);
-
-  /* record the frame size for later definition of the DW_AT_frame_base
-     attribute.  */
-  current_funcdef_frame_size = offset;
-
-  /* Define the rule for restoring the stack pointer.  */
-  if (frame_pointer_needed)
-    {
-      /* Restore the stack register from the frame pointer.  */
-      cfi = new_cfi ();
-      cfi->dw_cfi_opc = DW_CFA_register;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = STACK_POINTER_REGNUM;
-      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = FRAME_POINTER_REGNUM;
-      add_cfi (&fde->dw_fde_cfi, cfi);
-    }
-
-  /* If RA is saved on the stack, define it here.  */
-  if (regs_ever_live[31])
-    {
-      offset = current_frame_info.gp_save_offset / DWARF_CIE_DATA_ALIGNMENT;
-      assert (offset >= 0);
-      cfi = new_cfi ();
-      cfi->dw_cfi_opc = DW_CFA_offset_extended;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DW_FRAME_RA_COL;
-      cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
-      add_cfi (&fde->dw_fde_cfi, cfi);
-    }
-
-  /* If FP is saved on the stack, define it here.  */
-  if (current_frame_info.mask & (1 << 30))
-    {
-      offset = (current_frame_info.gp_save_offset
-                - (((current_frame_info.mask >> 31) & 1) * 4))
-               / DWARF_CIE_DATA_ALIGNMENT;
-      assert (offset >= 0);
-      cfi = new_cfi ();
-      cfi->dw_cfi_opc = DW_CFA_offset;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = FRAME_POINTER_REGNUM;
-      cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
-      add_cfi (&fde->dw_fde_cfi, cfi);
-    }
-
-#endif
-
-}
-
-/* Output a marker (i.e. a label) for the point in the generated code where
-   the real body of the function ends (just before the epilogue code).  */
-void
-dwarfout_end_function ()
-{
-  dw_fde_ref fde;
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  function_section (current_function_decl);
-  sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
-  ASM_OUTPUT_LABEL (asm_out_file, label);
-  /* Record the ending code location in the FDE.  */
-  fde = &fde_table[fde_table_in_use - 1];
-  fde->dw_fde_begin_epilogue = xstrdup(label);
 }
 
 /* Output a marker (i.e. a label) for the absolute end of the generated code
    for a function definition.  This gets called *after* the epilogue code has
    been generated.  */
+
 void
-dwarfout_end_epilogue ()
+dwarf2out_end_epilogue ()
 {
   dw_fde_ref fde;
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
   /* Output a label to mark the endpoint of the code generated for this
      function.        */
-  sprintf (label, FUNC_END_LABEL_FMT, current_funcdef_number);
+  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number);
   ASM_OUTPUT_LABEL (asm_out_file, label);
   fde = &fde_table[fde_table_in_use - 1];
   fde->dw_fde_end = xstrdup (label);
 }
 
 /* Lookup a filename (in the list of filenames that we know about here in
-   dwarfout.c) and return its "index".  The index of each (known) filename is
+   dwarf2out.c) and return its "index".  The index of each (known) filename is
    just a unique number which is associated with only that one filename.
    We need such numbers for the sake of generating labels
    (in the .debug_sfnames section) and references to those
@@ -7436,35 +8649,27 @@ dwarfout_end_epilogue ()
    add it to the list and assign it the next available unique index number.
    In order to speed up searches, we remember the index of the filename
    was looked up last.  This handles the majority of all searches.  */
+
 static unsigned
 lookup_filename (file_name)
      char *file_name;
 {
   static unsigned last_file_lookup_index = 0;
-  register char *fn;
   register unsigned i;
 
   /* Check to see if the file name that was searched on the previous call
      matches this file name. If so, return the index.  */
   if (last_file_lookup_index != 0)
-    {
-      fn = file_table[last_file_lookup_index];
-      if (strcmp (file_name, fn) == 0)
-       {
-         return last_file_lookup_index;
-       }
-    }
+    if (strcmp (file_name, file_table[last_file_lookup_index]) == 0)
+      return last_file_lookup_index;
 
   /* Didn't match the previous lookup, search the table */
   for (i = 1; i < file_table_in_use; ++i)
-    {
-      fn = file_table[i];
-      if (strcmp (file_name, fn) == 0)
-       {
-         last_file_lookup_index = i;
-         return i;
-       }
-    }
+    if (strcmp (file_name, file_table[i]) == 0)
+      {
+       last_file_lookup_index = i;
+       return i;
+      }
 
   /* Prepare to add a new table entry by making sure there is enough space in 
      the table to do so.  If not, expand the current table.  */
@@ -7472,78 +8677,113 @@ lookup_filename (file_name)
     {
       file_table_allocated += FILE_TABLE_INCREMENT;
       file_table
-       = (char **)
-       xrealloc (file_table, file_table_allocated * sizeof (char *));
+       = (char **) xrealloc (file_table,
+                             file_table_allocated * sizeof (char *));
     }
 
-  /* add the new entry to the end of the filename table.  */
+  /* Add the new entry to the end of the filename table.  */
   file_table[file_table_in_use] = xstrdup (file_name);
   last_file_lookup_index = file_table_in_use++;
+
   return last_file_lookup_index;
 }
 
 /* Output a label to mark the beginning of a source code line entry
    and record information relating to this source line, in
    'line_info_table' for later output of the .debug_line section.  */
+
 void
-dwarfout_line (filename, line)
+dwarf2out_line (filename, line)
      register char *filename;
      register unsigned line;
 {
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  register unsigned this_file_entry_num = lookup_filename (filename);
-  register dw_line_info_ref line_info;
   if (debug_info_level >= DINFO_LEVEL_NORMAL)
     {
       function_section (current_function_decl);
-      sprintf (label, LINE_CODE_LABEL_FMT, line_info_table_in_use);
-      ASM_OUTPUT_LABEL (asm_out_file, label);
-      fputc ('\n', asm_out_file);
 
-      /* expand the line info table if necessary */
-      if (line_info_table_in_use == line_info_table_allocated)
+      if (DECL_SECTION_NAME (current_function_decl))
+       {
+         register dw_separate_line_info_ref line_info;
+         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL,
+                                    separate_line_info_table_in_use);
+         fputc ('\n', asm_out_file);
+
+         /* expand the line info table if necessary */
+         if (separate_line_info_table_in_use
+             == separate_line_info_table_allocated)
+           {
+             separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
+             separate_line_info_table
+               = (dw_separate_line_info_ref)
+                 xrealloc (separate_line_info_table,
+                           separate_line_info_table_allocated
+                           * sizeof (dw_separate_line_info_entry));
+           }
+
+         /* Add the new entry at the end of the line_info_table.  */
+         line_info
+           = &separate_line_info_table[separate_line_info_table_in_use++];
+         line_info->dw_file_num = lookup_filename (filename);
+         line_info->dw_line_num = line;
+         line_info->function = current_funcdef_number;
+       }
+      else
        {
-         line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
-         line_info_table
-           = (dw_line_info_ref)
-           xrealloc (line_info_table,
-                  line_info_table_allocated * sizeof (dw_line_info_entry));
+         register dw_line_info_ref line_info;
+
+         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL,
+                                    line_info_table_in_use);
+         fputc ('\n', asm_out_file);
+
+         /* Expand the line info table if necessary.  */
+         if (line_info_table_in_use == line_info_table_allocated)
+           {
+             line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
+             line_info_table
+               = (dw_line_info_ref)
+                 xrealloc (line_info_table,
+                           (line_info_table_allocated
+                            * sizeof (dw_line_info_entry)));
+           }
+
+         /* Add the new entry at the end of the line_info_table.  */
+         line_info = &line_info_table[line_info_table_in_use++];
+         line_info->dw_file_num = lookup_filename (filename);
+         line_info->dw_line_num = line;
        }
-      /* add the new entry at the end of the line_info_table.  */
-      line_info = &line_info_table[line_info_table_in_use++];
-      line_info->dw_file_num = lookup_filename (filename);
-      line_info->dw_line_num = line;
     }
 }
 
 /* Record the beginning of a new source file, for later output
    of the .debug_macinfo section.  At present, unimplemented.  */
+
 void
-dwarfout_start_new_source_file (filename)
+dwarf2out_start_source_file (filename)
      register char *filename;
 {
 }
 
-/* Record the resumption of a source file, for later output
+/* Record the end of a source file, for later output
    of the .debug_macinfo section.  At present, unimplemented.  */
+
 void
-dwarfout_resume_previous_source_file (lineno)
-     register unsigned lineno;
+dwarf2out_end_source_file ()
 {
 }
 
 /* Called from check_newline in c-parse.y.  The `buffer' parameter contains
    the tail part of the directive line, i.e. the part which is past the
    initial whitespace, #, whitespace, directive-name, whitespace part.  */
+
 void
-dwarfout_define (lineno, buffer)
+dwarf2out_define (lineno, buffer)
      register unsigned lineno;
      register char *buffer;
 {
   static int initialized = 0;
   if (!initialized)
     {
-      dwarfout_start_new_source_file (primary_filename);
+      dwarf2out_start_source_file (primary_filename);
       initialized = 1;
     }
 }
@@ -7551,48 +8791,45 @@ dwarfout_define (lineno, buffer)
 /* Called from check_newline in c-parse.y.  The `buffer' parameter contains
    the tail part of the directive line, i.e. the part which is past the
    initial whitespace, #, whitespace, directive-name, whitespace part.  */
+
 void
-dwarfout_undef (lineno, buffer)
+dwarf2out_undef (lineno, buffer)
      register unsigned lineno;
      register char *buffer;
 {
 }
 
 /* Set up for Dwarf output at the start of compilation.  */
+
 void
-dwarfout_init (asm_out_file, main_input_filename)
+dwarf2out_init (asm_out_file, main_input_filename)
      register FILE *asm_out_file;
      register char *main_input_filename;
 {
-
   /* Remember the name of the primary input file.  */
   primary_filename = main_input_filename;
 
   /* Allocate the initial hunk of the file_table.  */
   file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *));
-  bzero (file_table, FILE_TABLE_INCREMENT * sizeof (char *));
+  bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *));
   file_table_allocated = FILE_TABLE_INCREMENT;
-  /* skip the first entry - file numbers begin at 1 */
-  file_table_in_use = 1;
 
-  /* Allocate the initial hunk of the type_die_table.  */
-  type_die_table
-    = (dw_die_ref *) xmalloc (TYPE_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
-  bzero (type_die_table, TYPE_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
-  type_die_table_allocated = TYPE_DIE_TABLE_INCREMENT;
-  type_die_table_in_use = 0;
+  /* Skip the first entry - file numbers begin at 1.  */
+  file_table_in_use = 1;
 
   /* Allocate the initial hunk of the decl_die_table.  */
   decl_die_table
     = (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
-  bzero (decl_die_table, DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
+  bzero ((char *) decl_die_table,
+        DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
   decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
   decl_die_table_in_use = 0;
 
   /* Allocate the initial hunk of the decl_scope_table.  */
   decl_scope_table
     = (tree *) xmalloc (DECL_SCOPE_TABLE_INCREMENT * sizeof (tree));
-  bzero (decl_scope_table, DECL_SCOPE_TABLE_INCREMENT * sizeof (tree));
+  bzero ((char *) decl_scope_table,
+        DECL_SCOPE_TABLE_INCREMENT * sizeof (tree));
   decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT;
   decl_scope_depth = 0;
 
@@ -7600,47 +8837,29 @@ dwarfout_init (asm_out_file, main_input_filename)
   abbrev_die_table
     = (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT
                              * sizeof (dw_die_ref));
-  bzero (abbrev_die_table, ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
+  bzero ((char *) abbrev_die_table,
+        ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
   abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
-  /* zero-th entry is allocated, but unused */
+  /* Zero-th entry is allocated, but unused */
   abbrev_die_table_in_use = 1;
 
   /* Allocate the initial hunk of the line_info_table.  */
   line_info_table
     = (dw_line_info_ref) xmalloc (LINE_INFO_TABLE_INCREMENT
                                  * sizeof (dw_line_info_entry));
-  bzero (line_info_table, LINE_INFO_TABLE_INCREMENT
-        * sizeof (dw_line_info_entry));
+  bzero ((char *) line_info_table,
+        LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
   line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
-  /* zero-th entry is allocated, but unused */
+  /* Zero-th entry is allocated, but unused */
   line_info_table_in_use = 1;
 
   /* Allocate the initial hunk of the fde_table.  */
-  fde_table = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
-  bzero (fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
+  fde_table
+    = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
+  bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
   fde_table_allocated = FDE_TABLE_INCREMENT;
   fde_table_in_use = 0;
 
-  /* Output a starting label for the .text section.  */
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION);
-  ASM_OUTPUT_LABEL (asm_out_file, TEXT_BEGIN_LABEL);
-
-  /* Output a starting label for the .data section.  */
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION);
-  ASM_OUTPUT_LABEL (asm_out_file, DATA_BEGIN_LABEL);
-
-  /* Output a starting label for the .rodata section.  */
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_SECTION (asm_out_file, RODATA_SECTION);
-  ASM_OUTPUT_LABEL (asm_out_file, RODATA_BEGIN_LABEL);
-
-  /* Output a starting label for the .bss section.  */
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION);
-  ASM_OUTPUT_LABEL (asm_out_file, BSS_BEGIN_LABEL);
-
   /* Generate the initial DIE for the .debug section.  Note that the (string) 
      value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE
      will (typically) be a relative pathname and that this pathname should be 
@@ -7648,21 +8867,24 @@ dwarfout_init (asm_out_file, main_input_filename)
      invoked when the given (base) source file was compiled.  */
   gen_compile_unit_die (main_input_filename);
 
-  /* clear the association between base types and their DIE's */
-  init_base_type_table ();
+  ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
 
-  /* clear the backchain list.  */
-  backchain = NULL;
+  /* Generate the CFA instructions common to all FDE's.  Do it now for the
+     sake of lookup_cfa.  */
+
+#ifdef INCOMING_RETURN_ADDR_RTX
+  /* On entry, the Canonical Frame Address is at SP+0.  */
+  dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, 0);
+  initial_return_save (INCOMING_RETURN_ADDR_RTX);
+#endif
 }
 
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
+
 void
-dwarfout_finish ()
+dwarf2out_finish ()
 {
-
-  resolve_backchains ();
-
   /* Traverse the DIE tree and add sibling attributes to those DIE's
      that have children.  */
   add_sibling_attributes (comp_unit_die);
@@ -7670,22 +8892,37 @@ dwarfout_finish ()
   /* Output a terminator label for the .text section.  */
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION);
-  ASM_OUTPUT_LABEL (asm_out_file, TEXT_END_LABEL);
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0);
 
+#if 0
   /* Output a terminator label for the .data section.  */
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION);
-  ASM_OUTPUT_LABEL (asm_out_file, DATA_END_LABEL);
-
-  /* Output a terminator label for the .rodata section.  */
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_SECTION (asm_out_file, RODATA_SECTION);
-  ASM_OUTPUT_LABEL (asm_out_file, RODATA_END_LABEL);
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0);
 
   /* Output a terminator label for the .bss section.  */
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION);
-  ASM_OUTPUT_LABEL (asm_out_file, BSS_END_LABEL);
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
+#endif
+
+  /* Output the source line correspondence table.  */
+  if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
+    {
+      fputc ('\n', asm_out_file);
+      ASM_OUTPUT_SECTION (asm_out_file, LINE_SECTION);
+      output_line_info ();
+
+      /* We can only use the low/high_pc attributes if all of the code
+        was in .text.  */
+      if (separate_line_info_table_in_use == 0)
+       {
+         add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, TEXT_SECTION);
+         add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
+       }
+
+      add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, LINE_SECTION);
+    }
 
   /* Output the abbreviation table.  */
   fputc ('\n', asm_out_file);
@@ -7693,17 +8930,11 @@ dwarfout_finish ()
   build_abbrev_table (comp_unit_die);
   output_abbrev_section ();
 
-  /* Output the source line correspondence table.  */
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_SECTION (asm_out_file, LINE_SECTION);
-  output_line_info ();
-
   /* Initialize the beginning DIE offset - and calculate sizes/offsets.   */
   next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
   calc_die_sizes (comp_unit_die);
 
-  /* Initialize the beginning FDE offset - and calculate sizes/offsets.  */
-  next_fde_offset = DWARF_CIE_SIZE;
+  /* calculate sizes/offsets for FDEs.  */
   calc_fde_sizes ();
 
   /* Output debugging information.  */
@@ -7712,22 +8943,26 @@ dwarfout_finish ()
   output_compilation_unit_header ();
   output_die (comp_unit_die);
 
-  if (fde_table_in_use)
+  if (pubname_table_in_use)
     {
-      /* Output call frame information.  */
-      fputc ('\n', asm_out_file);
-      ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
-      output_call_frame_info ();
-
       /* Output public names table.  */
       fputc ('\n', asm_out_file);
       ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION);
       output_pubnames ();
+    }
+
+  if (fde_table_in_use)
+    {
+      /* Output call frame information.  */
+      output_call_frame_info ();
 
       /* Output the address range information.  */
       fputc ('\n', asm_out_file);
       ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION);
       output_aranges ();
     }
+
+  /* The only DIE we should have with a parent of NULL is comp_unit_die.  */
+  assert (limbo_die_count == 1);
 }
-#endif /* DWARF_DEBUGGING_INFO  && DWARF_VERSION == 2 */
+#endif /* DWARF2_DEBUGGING_INFO */