x
authorJason Merrill <merrill@gnu.org>
Sat, 3 May 1997 01:50:08 +0000 (01:50 +0000)
committerJason Merrill <merrill@gnu.org>
Sat, 3 May 1997 01:50:08 +0000 (01:50 +0000)
From-SVN: r14014

gcc/dwarf2out.c

index cd7300d9c622135eba523c2f7fee069889d4d2f3..ebe892287fd81c7578cb40ac7f61dc0af5fb70a1 100644 (file)
@@ -22,7 +22,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "config.h"
 
-#ifdef DWARF2_DEBUGGING_INFO
+/* The first part of this file deals with the DWARF 2 frame unwind
+   information, which is also used by the GCC efficient exception handling
+   mechanism.  The second part, controlled only by an #ifdef
+   DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging
+   information.  */
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (INCOMING_RETURN_ADDR_RTX)
+
 #include <stdio.h>
 #include <setjmp.h>
 #include "dwarf2.h"
@@ -36,153 +43,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "output.h"
 #include "defaults.h"
 #include "expr.h"
+#include "except.h"
 
 /* #define NDEBUG 1 */
 #include "assert.h"
 
-extern char *getpwd ();
-
-/* 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.  */
-
 #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.
-   The types below are used to describe the internal representation.  */
-
-/* Each DIE may have a series of attribute/value pairs.  Values
-   can take on several forms.  The forms that are used in this
-   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_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 pubname_struct *pubname_ref;
-typedef dw_die_ref *arange_ref;
-
-/* Describe a double word constant value.  */
-
-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;
-}
-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
-   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_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_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;
-}
-dw_attr_node;
 
 /* Call frames are described using a sequence of Call Frame
    Information instructions.  The register number, offset
@@ -222,59 +94,6 @@ typedef struct dw_fde_struct
 }
 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;
-}
-die_node;
-
-/* The pubname structure */
-
-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 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;
-
 /* Maximum size (in bytes) of an artificially generated label.   */
 #define MAX_ARTIFICIAL_LABEL_BYTES     30
 
@@ -300,23 +119,10 @@ extern char *language_string;
 
 #define DWARF_VERSION 2
 
-/* Fixed size portion of the DWARF compilation unit header.  */
-#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 (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 \
-  (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE)
-
 /* Fixed size portion of the CIE (including the length field).  */
 #define DWARF_CIE_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 5)
 
@@ -334,206 +140,27 @@ static unsigned cie_size;
 /* Fixed size portion of the FDE.  */
 #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
-   purposes only.  Since GCC generates assembly language, we have
-   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
-
-/* Minimum line offset in a special line info. opcode.
-   This value was chosen to give a reasonable range of values.  */
-#define DWARF_LINE_BASE  -10
-
-/* First special line opcde - leave room for the standard opcodes.  */
-#define DWARF_LINE_OPCODE_BASE  10
-
-/* Range of line offsets in a special line info. opcode.  */
-#define DWARF_LINE_RANGE  (254-DWARF_LINE_OPCODE_BASE+1)
-
-/* Flag that indicates the initial value of the is_stmt_start flag.
-   In the present implementation, we do not mark any lines as
-   the beginning of a source statement, because that information
-   is not made available by the GCC front-end.  */
-#define        DWARF_LINE_DEFAULT_IS_STMT_START 1
-
-/* This location is used by calc_die_sizes() to keep track
-   the offset of each DIE within the .debug_info section.  */
-static unsigned long next_die_offset;
-
 /* This location is used by calc_fde_sizes() to keep track
    the offset of each FDE within the .debug_frame section.  */
 static unsigned long next_fde_offset;
 
-/* Record the root of the DIE's built for the current compilation unit.  */
-static dw_die_ref comp_unit_die;
+/* A pointer to the base of a table that contains frame description
+   information for each routine.  */
+static dw_fde_ref fde_table;
 
-/* The number of DIEs with a NULL parent waiting to be relocated.  */
-static int limbo_die_count;
+/* Number of elements currently allocated for fde_table.  */
+static unsigned fde_table_allocated;
 
-/* Pointer to an array of filenames referenced by this compilation unit.  */
-static char **file_table;
+/* Number of elements in fde_table currently in use.  */
+static unsigned fde_table_in_use;
 
-/* Total number of entries in the table (i.e. array) pointed to by
-   `file_table'.  This is the *total* and includes both used and unused
-   slots.  */
-static unsigned file_table_allocated;
-
-/* Number of entries in the file_table which are actually in use.  */
-static unsigned file_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the filename
-   table.  */
-#define FILE_TABLE_INCREMENT 64
-
-/* Local pointer to the name of the main input file.  Initialized in
-   dwarf2out_init.  */
-static char *primary_filename;
-
-/* For Dwarf output, we must assign lexical-blocks id numbers in the order in
-   which their beginnings are encountered. We output Dwarf debugging info
-   that refers to the beginnings and ends of the ranges of code for each
-   lexical block.  The labels themselves are generated in final.c, which
-   assigns numbers to the blocks in the same way.  */
-static unsigned next_block_number = 2;
-
-/* 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.  */
-static dw_die_ref *decl_die_table;
-
-/* Number of elements currently allocated for the decl_die_table.  */
-static unsigned decl_die_table_allocated;
-
-/* Number of elements in decl_die_table currently in use.  */
-static unsigned decl_die_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   decl_die_table.  */
-#define DECL_DIE_TABLE_INCREMENT 256
-
-/* A pointer to the base of a table of references to declaration
-   scopes.  This table is a display which tracks the nesting
-   of declaration scopes at the current scope and containing
-   scopes.  This table is used to find the proper place to
-   define type declaration DIE's.  */
-static tree *decl_scope_table;
-
-/* Number of elements currently allocated for the decl_scope_table.  */
-static unsigned decl_scope_table_allocated;
-
-/* Current level of nesting of declataion scopes.  */
-static unsigned decl_scope_depth;
-
-/* Size (in elements) of increments by which we may expand the
-   decl_scope_table.  */
-#define DECL_SCOPE_TABLE_INCREMENT 64
-
-/* A pointer to the base of a list of references to DIE's that
-   are uniquely identified by their tag, presence/absence of
-   children DIE's, and list of attribute/value pairs.  */
-static dw_die_ref *abbrev_die_table;
-
-/* Number of elements currently allocated for abbrev_die_table.  */
-static unsigned abbrev_die_table_allocated;
-
-/* Number of elements in type_die_table currently in use.  */
-static unsigned abbrev_die_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   abbrev_die_table.  */
-#define ABBREV_DIE_TABLE_INCREMENT 256
-
-/* A pointer to the base of a table that contains line information
-   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;
-
-/* Size (in elements) of increments by which we may expand the
-   line_info_table.  */
-#define LINE_INFO_TABLE_INCREMENT 1024
-
-/* A pointer to the base of a table that contains frame description
-   information for each routine.  */
-static dw_fde_ref fde_table;
-
-/* Number of elements currently allocated for fde_table.  */
-static unsigned fde_table_allocated;
-
-/* Number of elements in fde_table currently in use.  */
-static unsigned fde_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   fde_table.  */
-#define FDE_TABLE_INCREMENT 256
+/* Size (in elements) of increments by which we may expand the
+   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
@@ -547,119 +174,16 @@ static unsigned current_funcdef_number = 1;
    associated with the current function (body) definition.  */
 static unsigned current_funcdef_fde;
 
-/* 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
-   we want to tell the user what the source coordinates for the actual
-   declaration are.  */
-static tree dwarf_last_decl;
-
 /* Forward declarations for functions defined in this file.  */
 
 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 char *dwarf_cfi_name            PROTO((unsigned));
+static dw_cfi_ref new_cfi              PROTO((void));
+static void add_cfi                    PROTO((dw_cfi_ref *, dw_cfi_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 *,
@@ -672,87 +196,8 @@ 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 void output_call_frame_info     PROTO((int));
 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.
@@ -799,91 +244,19 @@ static unsigned lookup_filename           PROTO((char *));
 #define SECTION_FORMAT "\t%s\t%s\n"
 #endif
 
-/* Section names used to hold DWARF debugging information.  */
-#ifndef DEBUG_SECTION
-#define DEBUG_SECTION          ".debug_info"
-#endif
-#ifndef ABBREV_SECTION
-#define ABBREV_SECTION         ".debug_abbrev"
-#endif
-#ifndef ARANGES_SECTION
-#define ARANGES_SECTION                ".debug_aranges"
-#endif
-#ifndef DW_MACINFO_SECTION
-#define DW_MACINFO_SECTION     ".debug_macinfo"
-#endif
 #ifndef FRAME_SECTION
 #define FRAME_SECTION          ".debug_frame"
 #endif
-#ifndef LINE_SECTION
-#define LINE_SECTION           ".debug_line"
-#endif
-#ifndef LOC_SECTION
-#define LOC_SECTION            ".debug_loc"
-#endif
-#ifndef PUBNAMES_SECTION
-#define PUBNAMES_SECTION       ".debug_pubnames"
-#endif
-#ifndef STR_SECTION
-#define STR_SECTION            ".debug_str"
-#endif
-
-/* Standerd ELF section names for compiled code and data.  */
-#ifndef TEXT_SECTION
-#define TEXT_SECTION           ".text"
-#endif
-#ifndef DATA_SECTION
-#define DATA_SECTION           ".data"
-#endif
-#ifndef BSS_SECTION
-#define BSS_SECTION            ".bss"
+#if !defined (EH_FRAME_SECTION) && defined (ASM_OUTPUT_SECTION_NAME)
+#define EH_FRAME_SECTION       ".eh_frame"
 #endif
 
-
-/* Definitions of defaults for formats and names of various special
-   (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.  */
-
-char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
-
-#ifndef TEXT_END_LABEL
-#define TEXT_END_LABEL         "Letext"
-#endif
-#ifndef DATA_END_LABEL
-#define DATA_END_LABEL         "Ledata"
-#endif
-#ifndef BSS_END_LABEL
-#define BSS_END_LABEL           "Lebss"
-#endif
-#ifndef INSN_LABEL_FMT
-#define INSN_LABEL_FMT         "LI%u_"
-#endif
-#ifndef BLOCK_BEGIN_LABEL
-#define BLOCK_BEGIN_LABEL      "LBB"
-#endif
-#ifndef BLOCK_END_LABEL
-#define BLOCK_END_LABEL                "LBE"
-#endif
-#ifndef BODY_BEGIN_LABEL
-#define BODY_BEGIN_LABEL       "Lbb"
-#endif
-#ifndef BODY_END_LABEL
-#define BODY_END_LABEL         "Lbe"
-#endif
 #ifndef FUNC_BEGIN_LABEL
 #define FUNC_BEGIN_LABEL       "LFB"
 #endif
 #ifndef FUNC_END_LABEL
 #define FUNC_END_LABEL         "LFE"
 #endif
-#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,
@@ -992,47 +365,6 @@ char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
   } while (0)
 #endif
 
-/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
-   newline is produced.  When flag_verbose_asm is asserted, we add commnetary
-   at the end of the line, so we must avoid output of a newline here.  */
-#ifndef ASM_OUTPUT_DWARF_STRING
-#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
-  do {                                                                       \
-    register int slen = strlen(P);                                            \
-    register char *p = (P);                                                  \
-    register int i;                                                          \
-    fprintf (FILE, "\t.ascii \"");                                           \
-    for (i = 0; i < slen; i++)                                               \
-      {                                                                              \
-         register int c = p[i];                                              \
-         if (c == '\"' || c == '\\')                                         \
-           putc ('\\', FILE);                                                \
-         if (c >= ' ' && c < 0177)                                           \
-           putc (c, FILE);                                                   \
-         else                                                                \
-           {                                                                 \
-             fprintf (FILE, "\\%o", c);                                      \
-           }                                                                 \
-      }                                                                              \
-    fprintf (FILE, "\\0\"");                                                 \
-  }                                                                          \
-  while (0)
-#endif
-
-/* Convert a reference to the assembler name of a C-level name.  This
-   macro has the same effect as ASM_OUTPUT_LABELREF, but copies to
-   a string rather than writing to a file.  */
-#ifndef ASM_NAME_TO_STRING
-#define ASM_NAME_TO_STRING(STR, NAME) \
-  do {                                                                       \
-      if ((NAME)[0] == '*')                                                  \
-       strcpy (STR, NAME+1);                                                 \
-      else                                                                   \
-       strcpy (STR, NAME);                                                   \
-  }                                                                           \
-  while (0)
-#endif
-
 /* 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.  */
@@ -1049,7 +381,7 @@ char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
 #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.  */
 
@@ -1067,2620 +399,3621 @@ stripattributes (s)
   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.  */
+/* Return the register number described by a given RTL node.  */
 
-static void
-addr_const_to_string (str, x)
-     char *str;
-     rtx x;
+static unsigned
+reg_number (rtl)
+     register rtx rtl;
 {
-  char buf1[256];
-  char buf2[256];
+  register unsigned regno = REGNO (rtl);
 
-restart:
-  str[0] = '\0';
-  switch (GET_CODE (x))
+  if (regno >= FIRST_PSEUDO_REGISTER)
     {
-    case PC:
-      if (flag_pic)
-       strcat (str, ",");
-      else
-       abort ();
-      break;
-
-    case SYMBOL_REF:
-      ASM_NAME_TO_STRING (buf1, XSTR (x, 0));
-      strcat (str, buf1);
-      break;
-
-    case LABEL_REF:
-      ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
-      ASM_NAME_TO_STRING (buf2, buf1);
-      strcat (str, buf2);
-      break;
-
-    case CODE_LABEL:
-      ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x));
-      ASM_NAME_TO_STRING (buf2, buf1);
-      strcat (str, buf2);
-      break;
+      warning ("internal regno botch: regno = %d\n", regno);
+      regno = 0;
+    }
 
-    case CONST_INT:
-      sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
-      strcat (str, buf1);
-      break;
+  regno = DBX_REGISTER_NUMBER (regno);
+  return regno;
+}
 
-    case CONST:
-      /* This used to output parentheses around the expression, but that does 
-         not work on the 386 (either ATT or BSD assembler).  */
-      addr_const_to_string (buf1, XEXP (x, 0));
-      strcat (str, buf1);
-      break;
+/* Convert a DWARF call frame info. operation to its string name */
 
-    case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
-       {
-         /* We can use %d if the number is one word and positive.  */
-         if (CONST_DOUBLE_HIGH (x))
-           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, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
-         else
-           sprintf (buf1, HOST_WIDE_INT_PRINT_DEC,
-                    CONST_DOUBLE_LOW (x));
-         strcat (str, buf1);
-       }
-      else
-       /* We can't handle floating point constants; PRINT_OPERAND must
-          handle them.  */
-       output_operand_lossage ("floating constant misused");
-      break;
+static char *
+dwarf_cfi_name (cfi_opc)
+     register unsigned cfi_opc;
+{
+  switch (cfi_opc)
+    {
+    case DW_CFA_advance_loc:
+      return "DW_CFA_advance_loc";
+    case DW_CFA_offset:
+      return "DW_CFA_offset";
+    case DW_CFA_restore:
+      return "DW_CFA_restore";
+    case DW_CFA_nop:
+      return "DW_CFA_nop";
+    case DW_CFA_set_loc:
+      return "DW_CFA_set_loc";
+    case DW_CFA_advance_loc1:
+      return "DW_CFA_advance_loc1";
+    case DW_CFA_advance_loc2:
+      return "DW_CFA_advance_loc2";
+    case DW_CFA_advance_loc4:
+      return "DW_CFA_advance_loc4";
+    case DW_CFA_offset_extended:
+      return "DW_CFA_offset_extended";
+    case DW_CFA_restore_extended:
+      return "DW_CFA_restore_extended";
+    case DW_CFA_undefined:
+      return "DW_CFA_undefined";
+    case DW_CFA_same_value:
+      return "DW_CFA_same_value";
+    case DW_CFA_register:
+      return "DW_CFA_register";
+    case DW_CFA_remember_state:
+      return "DW_CFA_remember_state";
+    case DW_CFA_restore_state:
+      return "DW_CFA_restore_state";
+    case DW_CFA_def_cfa:
+      return "DW_CFA_def_cfa";
+    case DW_CFA_def_cfa_register:
+      return "DW_CFA_def_cfa_register";
+    case DW_CFA_def_cfa_offset:
+      return "DW_CFA_def_cfa_offset";
+    /* SGI/MIPS specific */
+    case DW_CFA_MIPS_advance_loc8:
+      return "DW_CFA_MIPS_advance_loc8";
+    default:
+      return "DW_CFA_<unknown>";
+    }
+}
 
-    case PLUS:
-      /* Some assemblers need integer constants to appear last (eg masm).  */
-      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
-       {
-         addr_const_to_string (buf1, XEXP (x, 1));
-         strcat (str, buf1);
-         if (INTVAL (XEXP (x, 0)) >= 0)
-           strcat (str, "+");
+/* Return a pointer to a newly allocated Call Frame Instruction.  */
 
-         addr_const_to_string (buf1, XEXP (x, 0));
-         strcat (str, buf1);
-       }
-      else
-       {
-         addr_const_to_string (buf1, XEXP (x, 0));
-         strcat (str, buf1);
-         if (INTVAL (XEXP (x, 1)) >= 0)
-           strcat (str, "+");
+static inline dw_cfi_ref
+new_cfi ()
+{
+  register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node));
 
-         addr_const_to_string (buf1, XEXP (x, 1));
-         strcat (str, buf1);
-       }
-      break;
+  cfi->dw_cfi_next = NULL;
+  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
+  cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
 
-    case MINUS:
-      /* Avoid outputting things like x-x or x+5-x, since some assemblers
-         can't handle that.  */
-      x = simplify_subtraction (x);
-      if (GET_CODE (x) != MINUS)
-       goto restart;
+  return cfi;
+}
 
-      addr_const_to_string (buf1, XEXP (x, 0));
-      strcat (str, buf1);
-      strcat (str, "-");
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) < 0)
-       {
-         strcat (str, ASM_OPEN_PAREN);
-         addr_const_to_string (buf1, XEXP (x, 1));
-         strcat (str, buf1);
-         strcat (str, ASM_CLOSE_PAREN);
-       }
-      else
-       {
-         addr_const_to_string (buf1, XEXP (x, 1));
-         strcat (str, buf1);
-       }
-      break;
+/* Add a Call Frame Instruction to list of instructions.  */
 
-    case ZERO_EXTEND:
-    case SIGN_EXTEND:
-      addr_const_to_string (buf1, XEXP (x, 0));
-      strcat (str, buf1);
-      break;
+static inline void
+add_cfi (list_head, cfi)
+     register dw_cfi_ref *list_head;
+     register dw_cfi_ref cfi;
+{
+  register dw_cfi_ref *p;
 
-    default:
-      output_operand_lossage ("invalid expression as operand");
-    }
+  /* Find the end of the chain.  */
+  for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
+    ;
+
+  *p = cfi;
 }
 
-/* Convert an address constant to a string, and return a pointer to
-   a copy of the result, located on the heap.  */
+/* Generate a new label for the CFI info to refer to.  */
 
 static char *
-addr_to_string (x)
-     rtx x;
+dwarf2out_cfi_label ()
 {
-  char buf[1024];
-  addr_const_to_string (buf, x);
-  return xstrdup (buf);
+  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;
 }
 
-/* Test if rtl node points to a psuedo register.  */
+/* Add CFI to the current fde at the PC value indicated by LABEL if specified,
+   or to the CIE if LABEL is NULL.  */
 
-static inline int
-is_pseudo_reg (rtl)
-     register rtx rtl;
+static void
+add_fde_cfi (label, cfi)
+     register char *label;
+     register dw_cfi_ref cfi;
 {
-  return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER))
-         || ((GET_CODE (rtl) == SUBREG)
-             && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
-}
+  if (label)
+    {
+      register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
 
-/* Return a reference to a type, with its const and volatile qualifiers
-   removed.  */
+      if (*label == 0)
+       label = dwarf2out_cfi_label ();
 
-static inline tree
-type_main_variant (type)
-     register tree type;
-{
-  type = TYPE_MAIN_VARIANT (type);
+      if (fde->dw_fde_current_label == NULL
+         || strcmp (label, fde->dw_fde_current_label) != 0)
+       {
+         register dw_cfi_ref xcfi;
 
-  /* There really should be only one main variant among any group of variants 
-     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.  */
+         fde->dw_fde_current_label = label = xstrdup (label);
 
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    while (type != TYPE_MAIN_VARIANT (type))
-      type = TYPE_MAIN_VARIANT (type);
+         /* 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);
+       }
 
-  return type;
+      add_cfi (&fde->dw_fde_cfi, cfi);
+    }
+
+  else
+    add_cfi (&cie_cfi_head, cfi);
 }
 
-/* Return non-zero if the given type node represents a tagged type.  */
+/* Subroutine of lookup_cfa.  */
 
-static inline int
-is_tagged_type (type)
-     register tree type;
+static inline void
+lookup_cfa_1 (cfi, regp, offsetp)
+     register dw_cfi_ref cfi;
+     register unsigned long *regp;
+     register long *offsetp;
 {
-  register enum tree_code code = TREE_CODE (type);
-
-  return (code == RECORD_TYPE || code == UNION_TYPE
-         || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
+  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;
+    }
 }
 
-/* Convert a DIE tag into its string name.  */
+/* Find the previous value for the CFA.  */
 
-static char *
-dwarf_tag_name (tag)
-     register unsigned tag;
+static void
+lookup_cfa (regp, offsetp)
+     register unsigned long *regp;
+     register long *offsetp;
 {
-  switch (tag)
+  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)
     {
-    case DW_TAG_padding:
-      return "DW_TAG_padding";
-    case DW_TAG_array_type:
-      return "DW_TAG_array_type";
-    case DW_TAG_class_type:
-      return "DW_TAG_class_type";
-    case DW_TAG_entry_point:
-      return "DW_TAG_entry_point";
-    case DW_TAG_enumeration_type:
-      return "DW_TAG_enumeration_type";
-    case DW_TAG_formal_parameter:
-      return "DW_TAG_formal_parameter";
-    case DW_TAG_imported_declaration:
-      return "DW_TAG_imported_declaration";
-    case DW_TAG_label:
-      return "DW_TAG_label";
-    case DW_TAG_lexical_block:
-      return "DW_TAG_lexical_block";
-    case DW_TAG_member:
-      return "DW_TAG_member";
-    case DW_TAG_pointer_type:
-      return "DW_TAG_pointer_type";
-    case DW_TAG_reference_type:
-      return "DW_TAG_reference_type";
-    case DW_TAG_compile_unit:
-      return "DW_TAG_compile_unit";
-    case DW_TAG_string_type:
-      return "DW_TAG_string_type";
-    case DW_TAG_structure_type:
-      return "DW_TAG_structure_type";
-    case DW_TAG_subroutine_type:
-      return "DW_TAG_subroutine_type";
-    case DW_TAG_typedef:
-      return "DW_TAG_typedef";
-    case DW_TAG_union_type:
-      return "DW_TAG_union_type";
-    case DW_TAG_unspecified_parameters:
-      return "DW_TAG_unspecified_parameters";
-    case DW_TAG_variant:
-      return "DW_TAG_variant";
-    case DW_TAG_common_block:
-      return "DW_TAG_common_block";
-    case DW_TAG_common_inclusion:
-      return "DW_TAG_common_inclusion";
-    case DW_TAG_inheritance:
-      return "DW_TAG_inheritance";
-    case DW_TAG_inlined_subroutine:
-      return "DW_TAG_inlined_subroutine";
-    case DW_TAG_module:
-      return "DW_TAG_module";
-    case DW_TAG_ptr_to_member_type:
-      return "DW_TAG_ptr_to_member_type";
-    case DW_TAG_set_type:
-      return "DW_TAG_set_type";
-    case DW_TAG_subrange_type:
-      return "DW_TAG_subrange_type";
-    case DW_TAG_with_stmt:
-      return "DW_TAG_with_stmt";
-    case DW_TAG_access_declaration:
-      return "DW_TAG_access_declaration";
-    case DW_TAG_base_type:
-      return "DW_TAG_base_type";
-    case DW_TAG_catch_block:
-      return "DW_TAG_catch_block";
-    case DW_TAG_const_type:
-      return "DW_TAG_const_type";
-    case DW_TAG_constant:
-      return "DW_TAG_constant";
-    case DW_TAG_enumerator:
-      return "DW_TAG_enumerator";
-    case DW_TAG_file_type:
-      return "DW_TAG_file_type";
-    case DW_TAG_friend:
-      return "DW_TAG_friend";
-    case DW_TAG_namelist:
-      return "DW_TAG_namelist";
-    case DW_TAG_namelist_item:
-      return "DW_TAG_namelist_item";
-    case DW_TAG_packed_type:
-      return "DW_TAG_packed_type";
-    case DW_TAG_subprogram:
-      return "DW_TAG_subprogram";
-    case DW_TAG_template_type_param:
-      return "DW_TAG_template_type_param";
-    case DW_TAG_template_value_param:
-      return "DW_TAG_template_value_param";
-    case DW_TAG_thrown_type:
-      return "DW_TAG_thrown_type";
-    case DW_TAG_try_block:
-      return "DW_TAG_try_block";
-    case DW_TAG_variant_part:
-      return "DW_TAG_variant_part";
-    case DW_TAG_variable:
-      return "DW_TAG_variable";
-    case DW_TAG_volatile_type:
-      return "DW_TAG_volatile_type";
-    case DW_TAG_MIPS_loop:
-      return "DW_TAG_MIPS_loop";
-    case DW_TAG_format_label:
-      return "DW_TAG_format_label";
-    case DW_TAG_function_template:
-      return "DW_TAG_function_template";
-    case DW_TAG_class_template:
-      return "DW_TAG_class_template";
-    default:
-      return "DW_TAG_<unknown>";
+      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);
     }
 }
 
-/* Convert a DWARF attribute code into its string name.  */
+/* The current rule for calculating the DWARF2 canonical frame address.  */
+static unsigned cfa_reg;
+static long cfa_offset;
 
-static char *
-dwarf_attr_name (attr)
-     register unsigned attr;
+/* 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;
+
+/* 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;
 {
-  switch (attr)
+  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)
     {
-    case DW_AT_sibling:
-      return "DW_AT_sibling";
-    case DW_AT_location:
-      return "DW_AT_location";
-    case DW_AT_name:
-      return "DW_AT_name";
-    case DW_AT_ordering:
-      return "DW_AT_ordering";
-    case DW_AT_subscr_data:
-      return "DW_AT_subscr_data";
-    case DW_AT_byte_size:
-      return "DW_AT_byte_size";
-    case DW_AT_bit_offset:
-      return "DW_AT_bit_offset";
-    case DW_AT_bit_size:
-      return "DW_AT_bit_size";
-    case DW_AT_element_list:
-      return "DW_AT_element_list";
-    case DW_AT_stmt_list:
-      return "DW_AT_stmt_list";
-    case DW_AT_low_pc:
-      return "DW_AT_low_pc";
-    case DW_AT_high_pc:
-      return "DW_AT_high_pc";
-    case DW_AT_language:
-      return "DW_AT_language";
-    case DW_AT_member:
-      return "DW_AT_member";
-    case DW_AT_discr:
-      return "DW_AT_discr";
-    case DW_AT_discr_value:
-      return "DW_AT_discr_value";
-    case DW_AT_visibility:
-      return "DW_AT_visibility";
-    case DW_AT_import:
-      return "DW_AT_import";
-    case DW_AT_string_length:
-      return "DW_AT_string_length";
-    case DW_AT_common_reference:
-      return "DW_AT_common_reference";
-    case DW_AT_comp_dir:
-      return "DW_AT_comp_dir";
-    case DW_AT_const_value:
-      return "DW_AT_const_value";
-    case DW_AT_containing_type:
-      return "DW_AT_containing_type";
-    case DW_AT_default_value:
-      return "DW_AT_default_value";
-    case DW_AT_inline:
-      return "DW_AT_inline";
-    case DW_AT_is_optional:
-      return "DW_AT_is_optional";
-    case DW_AT_lower_bound:
-      return "DW_AT_lower_bound";
-    case DW_AT_producer:
-      return "DW_AT_producer";
-    case DW_AT_prototyped:
-      return "DW_AT_prototyped";
-    case DW_AT_return_addr:
-      return "DW_AT_return_addr";
-    case DW_AT_start_scope:
-      return "DW_AT_start_scope";
-    case DW_AT_stride_size:
-      return "DW_AT_stride_size";
-    case DW_AT_upper_bound:
-      return "DW_AT_upper_bound";
-    case DW_AT_abstract_origin:
-      return "DW_AT_abstract_origin";
-    case DW_AT_accessibility:
-      return "DW_AT_accessibility";
-    case DW_AT_address_class:
-      return "DW_AT_address_class";
-    case DW_AT_artificial:
-      return "DW_AT_artificial";
-    case DW_AT_base_types:
-      return "DW_AT_base_types";
-    case DW_AT_calling_convention:
-      return "DW_AT_calling_convention";
-    case DW_AT_count:
-      return "DW_AT_count";
-    case DW_AT_data_member_location:
-      return "DW_AT_data_member_location";
-    case DW_AT_decl_column:
-      return "DW_AT_decl_column";
-    case DW_AT_decl_file:
-      return "DW_AT_decl_file";
-    case DW_AT_decl_line:
-      return "DW_AT_decl_line";
-    case DW_AT_declaration:
-      return "DW_AT_declaration";
-    case DW_AT_discr_list:
-      return "DW_AT_discr_list";
-    case DW_AT_encoding:
-      return "DW_AT_encoding";
-    case DW_AT_external:
-      return "DW_AT_external";
-    case DW_AT_frame_base:
-      return "DW_AT_frame_base";
-    case DW_AT_friend:
-      return "DW_AT_friend";
-    case DW_AT_identifier_case:
-      return "DW_AT_identifier_case";
-    case DW_AT_macro_info:
-      return "DW_AT_macro_info";
-    case DW_AT_namelist_items:
-      return "DW_AT_namelist_items";
-    case DW_AT_priority:
-      return "DW_AT_priority";
-    case DW_AT_segment:
-      return "DW_AT_segment";
-    case DW_AT_specification:
-      return "DW_AT_specification";
-    case DW_AT_static_link:
-      return "DW_AT_static_link";
-    case DW_AT_type:
-      return "DW_AT_type";
-    case DW_AT_use_location:
-      return "DW_AT_use_location";
-    case DW_AT_variable_parameter:
-      return "DW_AT_variable_parameter";
-    case DW_AT_virtuality:
-      return "DW_AT_virtuality";
-    case DW_AT_vtable_elem_location:
-      return "DW_AT_vtable_elem_location";
+      cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
+      cfi->dw_cfi_oprnd1.dw_cfi_offset = offset;
+    }
 
-    case DW_AT_MIPS_fde:
-      return "DW_AT_MIPS_fde";
-    case DW_AT_MIPS_loop_begin:
-      return "DW_AT_MIPS_loop_begin";
-    case DW_AT_MIPS_tail_loop_begin:
-      return "DW_AT_MIPS_tail_loop_begin";
-    case DW_AT_MIPS_epilog_begin:
-      return "DW_AT_MIPS_epilog_begin";
-    case DW_AT_MIPS_loop_unroll_factor:
-      return "DW_AT_MIPS_loop_unroll_factor";
-    case DW_AT_MIPS_software_pipeline_depth:
-      return "DW_AT_MIPS_software_pipeline_depth";
-    case DW_AT_MIPS_linkage_name:
-      return "DW_AT_MIPS_linkage_name";
-    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";
+#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
 
-    case DW_AT_sf_names:
-      return "DW_AT_sf_names";
-    case DW_AT_src_info:
-      return "DW_AT_src_info";
-    case DW_AT_mac_info:
-      return "DW_AT_mac_info";
-    case DW_AT_src_coords:
-      return "DW_AT_src_coords";
-    case DW_AT_body_begin:
-      return "DW_AT_body_begin";
-    case DW_AT_body_end:
-      return "DW_AT_body_end";
-    default:
-      return "DW_AT_<unknown>";
+  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);
+
+  cfa_reg = reg;
+  cfa_offset = offset;
+  if (cfa_store_reg == reg)
+    cfa_store_offset = offset;
 }
 
-/* Convert a DWARF value form code into its string name.  */
+/* 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 char *
-dwarf_form_name (form)
-     register unsigned form;
+static void
+reg_save (label, reg, sreg, offset)
+     register char * label;
+     register unsigned reg;
+     register unsigned sreg;
+     register long offset;
 {
-  switch (form)
+  register dw_cfi_ref cfi = new_cfi ();
+
+  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+
+  if (sreg == -1)
     {
-    case DW_FORM_addr:
-      return "DW_FORM_addr";
-    case DW_FORM_block2:
-      return "DW_FORM_block2";
-    case DW_FORM_block4:
-      return "DW_FORM_block4";
-    case DW_FORM_data2:
-      return "DW_FORM_data2";
-    case DW_FORM_data4:
-      return "DW_FORM_data4";
-    case DW_FORM_data8:
-      return "DW_FORM_data8";
-    case DW_FORM_string:
-      return "DW_FORM_string";
-    case DW_FORM_block:
-      return "DW_FORM_block";
-    case DW_FORM_block1:
-      return "DW_FORM_block1";
-    case DW_FORM_data1:
-      return "DW_FORM_data1";
-    case DW_FORM_flag:
-      return "DW_FORM_flag";
-    case DW_FORM_sdata:
-      return "DW_FORM_sdata";
-    case DW_FORM_strp:
-      return "DW_FORM_strp";
-    case DW_FORM_udata:
-      return "DW_FORM_udata";
-    case DW_FORM_ref_addr:
-      return "DW_FORM_ref_addr";
-    case DW_FORM_ref1:
-      return "DW_FORM_ref1";
-    case DW_FORM_ref2:
-      return "DW_FORM_ref2";
-    case DW_FORM_ref4:
-      return "DW_FORM_ref4";
-    case DW_FORM_ref8:
-      return "DW_FORM_ref8";
-    case DW_FORM_ref_udata:
-      return "DW_FORM_ref_udata";
-    case DW_FORM_indirect:
-      return "DW_FORM_indirect";
+      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:
-      return "DW_FORM_<unknown>";
+      abort ();
     }
+
+  reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset);
 }
 
-/* Convert a DWARF stack opcode into its string name.  */
+/* 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.  */
 
-static char *
-dwarf_stack_op_name (op)
-     register unsigned op;
+void
+dwarf2out_frame_debug (insn)
+     rtx insn;
 {
-  switch (op)
+  char *label;
+  rtx src, dest;
+  long 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)
     {
-    case DW_OP_addr:
-      return "DW_OP_addr";
-    case DW_OP_deref:
-      return "DW_OP_deref";
-    case DW_OP_const1u:
-      return "DW_OP_const1u";
-    case DW_OP_const1s:
-      return "DW_OP_const1s";
-    case DW_OP_const2u:
-      return "DW_OP_const2u";
-    case DW_OP_const2s:
-      return "DW_OP_const2s";
-    case DW_OP_const4u:
-      return "DW_OP_const4u";
-    case DW_OP_const4s:
-      return "DW_OP_const4s";
-    case DW_OP_const8u:
-      return "DW_OP_const8u";
-    case DW_OP_const8s:
-      return "DW_OP_const8s";
-    case DW_OP_constu:
-      return "DW_OP_constu";
-    case DW_OP_consts:
-      return "DW_OP_consts";
-    case DW_OP_dup:
-      return "DW_OP_dup";
-    case DW_OP_drop:
-      return "DW_OP_drop";
-    case DW_OP_over:
-      return "DW_OP_over";
-    case DW_OP_pick:
-      return "DW_OP_pick";
-    case DW_OP_swap:
-      return "DW_OP_swap";
-    case DW_OP_rot:
-      return "DW_OP_rot";
-    case DW_OP_xderef:
-      return "DW_OP_xderef";
-    case DW_OP_abs:
-      return "DW_OP_abs";
-    case DW_OP_and:
-      return "DW_OP_and";
-    case DW_OP_div:
-      return "DW_OP_div";
-    case DW_OP_minus:
-      return "DW_OP_minus";
-    case DW_OP_mod:
-      return "DW_OP_mod";
-    case DW_OP_mul:
-      return "DW_OP_mul";
-    case DW_OP_neg:
-      return "DW_OP_neg";
-    case DW_OP_not:
-      return "DW_OP_not";
-    case DW_OP_or:
-      return "DW_OP_or";
-    case DW_OP_plus:
-      return "DW_OP_plus";
-    case DW_OP_plus_uconst:
-      return "DW_OP_plus_uconst";
-    case DW_OP_shl:
-      return "DW_OP_shl";
-    case DW_OP_shr:
-      return "DW_OP_shr";
-    case DW_OP_shra:
-      return "DW_OP_shra";
-    case DW_OP_xor:
-      return "DW_OP_xor";
-    case DW_OP_bra:
-      return "DW_OP_bra";
-    case DW_OP_eq:
-      return "DW_OP_eq";
-    case DW_OP_ge:
-      return "DW_OP_ge";
-    case DW_OP_gt:
-      return "DW_OP_gt";
-    case DW_OP_le:
-      return "DW_OP_le";
-    case DW_OP_lt:
-      return "DW_OP_lt";
-    case DW_OP_ne:
-      return "DW_OP_ne";
-    case DW_OP_skip:
-      return "DW_OP_skip";
-    case DW_OP_lit0:
-      return "DW_OP_lit0";
-    case DW_OP_lit1:
-      return "DW_OP_lit1";
-    case DW_OP_lit2:
-      return "DW_OP_lit2";
-    case DW_OP_lit3:
-      return "DW_OP_lit3";
-    case DW_OP_lit4:
-      return "DW_OP_lit4";
-    case DW_OP_lit5:
-      return "DW_OP_lit5";
-    case DW_OP_lit6:
-      return "DW_OP_lit6";
-    case DW_OP_lit7:
-      return "DW_OP_lit7";
-    case DW_OP_lit8:
-      return "DW_OP_lit8";
-    case DW_OP_lit9:
-      return "DW_OP_lit9";
-    case DW_OP_lit10:
-      return "DW_OP_lit10";
-    case DW_OP_lit11:
-      return "DW_OP_lit11";
-    case DW_OP_lit12:
-      return "DW_OP_lit12";
-    case DW_OP_lit13:
-      return "DW_OP_lit13";
-    case DW_OP_lit14:
-      return "DW_OP_lit14";
-    case DW_OP_lit15:
-      return "DW_OP_lit15";
-    case DW_OP_lit16:
-      return "DW_OP_lit16";
-    case DW_OP_lit17:
-      return "DW_OP_lit17";
-    case DW_OP_lit18:
-      return "DW_OP_lit18";
-    case DW_OP_lit19:
-      return "DW_OP_lit19";
-    case DW_OP_lit20:
-      return "DW_OP_lit20";
-    case DW_OP_lit21:
-      return "DW_OP_lit21";
-    case DW_OP_lit22:
-      return "DW_OP_lit22";
-    case DW_OP_lit23:
-      return "DW_OP_lit23";
-    case DW_OP_lit24:
-      return "DW_OP_lit24";
-    case DW_OP_lit25:
-      return "DW_OP_lit25";
-    case DW_OP_lit26:
-      return "DW_OP_lit26";
-    case DW_OP_lit27:
-      return "DW_OP_lit27";
-    case DW_OP_lit28:
-      return "DW_OP_lit28";
-    case DW_OP_lit29:
-      return "DW_OP_lit29";
-    case DW_OP_lit30:
-      return "DW_OP_lit30";
-    case DW_OP_lit31:
-      return "DW_OP_lit31";
-    case DW_OP_reg0:
-      return "DW_OP_reg0";
-    case DW_OP_reg1:
-      return "DW_OP_reg1";
-    case DW_OP_reg2:
-      return "DW_OP_reg2";
-    case DW_OP_reg3:
-      return "DW_OP_reg3";
-    case DW_OP_reg4:
-      return "DW_OP_reg4";
-    case DW_OP_reg5:
-      return "DW_OP_reg5";
-    case DW_OP_reg6:
-      return "DW_OP_reg6";
-    case DW_OP_reg7:
-      return "DW_OP_reg7";
-    case DW_OP_reg8:
-      return "DW_OP_reg8";
-    case DW_OP_reg9:
-      return "DW_OP_reg9";
-    case DW_OP_reg10:
-      return "DW_OP_reg10";
-    case DW_OP_reg11:
-      return "DW_OP_reg11";
-    case DW_OP_reg12:
-      return "DW_OP_reg12";
-    case DW_OP_reg13:
-      return "DW_OP_reg13";
-    case DW_OP_reg14:
-      return "DW_OP_reg14";
-    case DW_OP_reg15:
-      return "DW_OP_reg15";
-    case DW_OP_reg16:
-      return "DW_OP_reg16";
-    case DW_OP_reg17:
-      return "DW_OP_reg17";
-    case DW_OP_reg18:
-      return "DW_OP_reg18";
-    case DW_OP_reg19:
-      return "DW_OP_reg19";
-    case DW_OP_reg20:
-      return "DW_OP_reg20";
-    case DW_OP_reg21:
-      return "DW_OP_reg21";
-    case DW_OP_reg22:
-      return "DW_OP_reg22";
-    case DW_OP_reg23:
-      return "DW_OP_reg23";
-    case DW_OP_reg24:
-      return "DW_OP_reg24";
-    case DW_OP_reg25:
-      return "DW_OP_reg25";
-    case DW_OP_reg26:
-      return "DW_OP_reg26";
-    case DW_OP_reg27:
-      return "DW_OP_reg27";
-    case DW_OP_reg28:
-      return "DW_OP_reg28";
-    case DW_OP_reg29:
-      return "DW_OP_reg29";
-    case DW_OP_reg30:
-      return "DW_OP_reg30";
-    case DW_OP_reg31:
-      return "DW_OP_reg31";
-    case DW_OP_breg0:
-      return "DW_OP_breg0";
-    case DW_OP_breg1:
-      return "DW_OP_breg1";
-    case DW_OP_breg2:
-      return "DW_OP_breg2";
-    case DW_OP_breg3:
-      return "DW_OP_breg3";
-    case DW_OP_breg4:
-      return "DW_OP_breg4";
-    case DW_OP_breg5:
-      return "DW_OP_breg5";
-    case DW_OP_breg6:
-      return "DW_OP_breg6";
-    case DW_OP_breg7:
-      return "DW_OP_breg7";
-    case DW_OP_breg8:
-      return "DW_OP_breg8";
-    case DW_OP_breg9:
-      return "DW_OP_breg9";
-    case DW_OP_breg10:
-      return "DW_OP_breg10";
-    case DW_OP_breg11:
-      return "DW_OP_breg11";
-    case DW_OP_breg12:
-      return "DW_OP_breg12";
-    case DW_OP_breg13:
-      return "DW_OP_breg13";
-    case DW_OP_breg14:
-      return "DW_OP_breg14";
-    case DW_OP_breg15:
-      return "DW_OP_breg15";
-    case DW_OP_breg16:
-      return "DW_OP_breg16";
-    case DW_OP_breg17:
-      return "DW_OP_breg17";
-    case DW_OP_breg18:
-      return "DW_OP_breg18";
-    case DW_OP_breg19:
-      return "DW_OP_breg19";
-    case DW_OP_breg20:
-      return "DW_OP_breg20";
-    case DW_OP_breg21:
-      return "DW_OP_breg21";
-    case DW_OP_breg22:
-      return "DW_OP_breg22";
-    case DW_OP_breg23:
-      return "DW_OP_breg23";
-    case DW_OP_breg24:
-      return "DW_OP_breg24";
-    case DW_OP_breg25:
-      return "DW_OP_breg25";
-    case DW_OP_breg26:
-      return "DW_OP_breg26";
-    case DW_OP_breg27:
-      return "DW_OP_breg27";
-    case DW_OP_breg28:
-      return "DW_OP_breg28";
-    case DW_OP_breg29:
-      return "DW_OP_breg29";
-    case DW_OP_breg30:
-      return "DW_OP_breg30";
-    case DW_OP_breg31:
-      return "DW_OP_breg31";
-    case DW_OP_regx:
-      return "DW_OP_regx";
-    case DW_OP_fbreg:
-      return "DW_OP_fbreg";
-    case DW_OP_bregx:
-      return "DW_OP_bregx";
-    case DW_OP_piece:
-      return "DW_OP_piece";
-    case DW_OP_deref_size:
-      return "DW_OP_deref_size";
-    case DW_OP_xderef_size:
-      return "DW_OP_xderef_size";
-    case DW_OP_nop:
-      return "DW_OP_nop";
+      /* 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 ();
+    }
+}
+
+/* Return the size of an unsigned LEB128 quantity.  */
+
+static inline unsigned long
+size_of_uleb128 (value)
+     register unsigned long value;
+{
+  register unsigned long size = 0;
+  register unsigned byte;
+
+  do
+    {
+      byte = (value & 0x7f);
+      value >>= 7;
+      size += 1;
+    }
+  while (value != 0);
+
+  return size;
+}
+
+/* Return the size of a signed LEB128 quantity.  */
+
+static inline unsigned long
+size_of_sleb128 (value)
+     register long value;
+{
+  register unsigned long size = 0;
+  register unsigned byte;
+
+  do
+    {
+      byte = (value & 0x7f);
+      value >>= 7;
+      size += 1;
+    }
+  while (!(((value == 0) && ((byte & 0x40) == 0))
+          || ((value == -1) && ((byte & 0x40) != 0))));
+
+  return size;
+}
+
+/* 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 */
+  size = 1;
+  switch (cfi->dw_cfi_opc)
+    {
+    case DW_CFA_offset:
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
+      break;
+    case DW_CFA_set_loc:
+      size += PTR_SIZE;
+      break;
+    case DW_CFA_advance_loc1:
+      size += 1;
+      break;
+    case DW_CFA_advance_loc2:
+      size += 2;
+      break;
+    case DW_CFA_advance_loc4:
+      size += 4;
+      break;
+#ifdef MIPS_DEBUGGING_INFO
+    case DW_CFA_MIPS_advance_loc8:
+      size += 8;
+      break;
+#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);
+      break;
+    case DW_CFA_restore_extended:
+    case DW_CFA_undefined:
+      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);
+      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);
+      break;
+    case DW_CFA_def_cfa_offset:
+      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+      break;
     default:
-      return "OP_<unknown>";
+      break;
+    }
+
+    return size;
+}
+
+/* Return the size of an FDE sans the length word.  */
+
+static inline unsigned long
+size_of_fde (fde, npad)
+    dw_fde_ref fde;
+    unsigned long *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 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];
+      fde->dw_fde_offset = next_fde_offset;
+      fde_size = size_of_fde (fde, &fde_pad);
+      next_fde_offset += fde_size;
+    }
+}
+
+/* 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;
+
+      fprintf (asm_out_file, "0x%x", byte);
+      if (value != 0)
+       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
+    {
+      byte = (value & 0x7f);
+      /* arithmetic shift */
+      value >>= 7;
+      more = !((((value == 0) && ((byte & 0x40) == 0))
+               || ((value == -1) && ((byte & 0x40) != 0))));
+      if (more)
+       byte |= 0x80;
+
+      fprintf (asm_out_file, "0x%x", byte);
+      if (more)
+       fprintf (asm_out_file, ",");
+    }
+
+  while (more);
+  if (flag_verbose_asm)
+    fprintf (asm_out_file, "\t%s SLEB128 %d", ASM_COMMENT_START, save_value);
+}
+
+/* Output a Call Frame Information opcode and its operand(s).  */
+
+static void
+output_cfi (cfi, fde)
+     register dw_cfi_ref cfi;
+     register dw_fde_ref fde;
+{
+  if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
+    {
+      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+                             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 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, 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);
+      fputc ('\n', asm_out_file);
+    }
+  else if (cfi->dw_cfi_opc == DW_CFA_restore)
+    {
+      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_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));
+
+      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);
+          fputc ('\n', asm_out_file);
+         break;
+       case DW_CFA_advance_loc1:
+         /* TODO: not currently implemented.  */
+         abort ();
+         break;
+       case DW_CFA_advance_loc2:
+          ASM_OUTPUT_DWARF_DELTA2 (asm_out_file,
+                                  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_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:
+         /* TODO: not currently implemented.  */
+         abort ();
+         break;
+#endif
+       case DW_CFA_offset_extended:
+       case DW_CFA_def_cfa:
+         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+          fputc ('\n', asm_out_file);
+         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);
+          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);
+          fputc ('\n', asm_out_file);
+         break;
+       case DW_CFA_register:
+         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);
+          fputc ('\n', asm_out_file);
+         break;
+       case DW_CFA_def_cfa_offset:
+         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+          fputc ('\n', asm_out_file);
+         break;
+       default:
+         break;
+       }
+     }
+}
+
+/* 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 (for_eh)
+     int for_eh;
+{
+  register unsigned long i, j;
+  register dw_fde_ref fde;
+  register unsigned long fde_size;
+  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);
+  if (for_eh)
+    {
+#ifdef EH_FRAME_SECTION
+      ASM_OUTPUT_SECTION_NAME (asm_out_file, NULL_TREE, EH_FRAME_SECTION, 0);
+#else
+      data_section ();
+#endif
+      assemble_label ("__FRAME_BEGIN__");
+    }
+  else
+    ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
+
+  /* Output the CIE. */
+  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);
+
+  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)
+    {
+      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
+      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);
+
+  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);
+
+  fputc ('\n', asm_out_file);
+  output_uleb128 (1);
+  if (flag_verbose_asm)
+    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, " (CIE Data Alignment Factor)");
+
+  fputc ('\n', asm_out_file);
+  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);
+
+  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 = 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);
+
+      fputc ('\n', asm_out_file);
+    }
+
+  /* Loop through all of the FDE's.  */
+  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_DATA (asm_out_file, fde_size - DWARF_OFFSET_SIZE);
+      if (flag_verbose_asm)
+       fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
+
+      fputc ('\n', asm_out_file);
+      if (for_eh)
+       ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__FRAME_BEGIN__");
+      else
+       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);
+
+      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);
+
+      fputc ('\n', asm_out_file);
+      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);
+
+      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);
+
+      /* 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);
+
+         fputc ('\n', asm_out_file);
+       }
+    }
+#ifndef EH_FRAME_SECTION
+  if (for_eh)
+    {
+      /* Emit terminating zero for table.  */
+      ASM_OUTPUT_DWARF_DATA (asm_out_file, 0);
+      fputc ('\n', asm_out_file);
+    }
+#endif
+}
+
+/* Output a marker (i.e. a label) for the beginning of a function, before
+   the prologue.  */
+
+void
+dwarf2out_begin_prologue ()
+{
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+  register dw_fde_ref fde;
+
+  function_section (current_function_decl);
+  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));
     }
+
+  /* Record the FDE associated with this function.  */
+  current_funcdef_fde = fde_table_in_use;
+
+  /* Add the new FDE at the end of the fde_table.  */
+  fde = &fde_table[fde_table_in_use++];
+  fde->dw_fde_begin = xstrdup (label);
+  fde->dw_fde_current_label = NULL;
+  fde->dw_fde_end = NULL;
+  fde->dw_fde_cfi = NULL;
+}
+
+/* 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
+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.        */
+  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);
+
+  ++current_funcdef_number;
+}
+
+void
+dwarf2out_frame_init ()
+{
+  /* Allocate the initial hunk of the fde_table.  */
+  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;
+
+  /* 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
+}
+
+void
+dwarf2out_frame_finish ()
+{
+  /* calculate sizes/offsets for FDEs.  */
+  calc_fde_sizes ();
+
+  /* Output call frame information.  */
+  if (write_symbols == DWARF2_DEBUG)
+    output_call_frame_info (0);
+  if (flag_exceptions && ! exceptions_via_longjmp)
+    output_call_frame_info (1);
+}  
+
+#endif /* .debug_frame support */
+
+/* And now, the support for symbolic debugging information.  */
+#ifdef DWARF2_DEBUGGING_INFO
+
+extern char *getpwd ();
+
+/* 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.  */
+
+/* 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.
+   The types below are used to describe the internal representation.  */
+
+/* Each DIE may have a series of attribute/value pairs.  Values
+   can take on several forms.  The forms that are used in this
+   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_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;
 
-/* Convert a DWARF type code into its string name.  */
+/* Various DIE's use offsets relative to the beginning of the
+   .debug_info section to refer to each other.  */
 
-static char *
-dwarf_type_encoding_name (enc)
-     register unsigned enc;
+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 pubname_struct *pubname_ref;
+typedef dw_die_ref *arange_ref;
+
+/* Describe a double word constant value.  */
+
+typedef struct dw_long_long_struct
 {
-  switch (enc)
+  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;
+}
+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
+   represented internally.  */
+
+typedef struct dw_val_struct
+{
+  dw_val_class val_class;
+  union
     {
-    case DW_ATE_address:
-      return "DW_ATE_address";
-    case DW_ATE_boolean:
-      return "DW_ATE_boolean";
-    case DW_ATE_complex_float:
-      return "DW_ATE_complex_float";
-    case DW_ATE_float:
-      return "DW_ATE_float";
-    case DW_ATE_signed:
-      return "DW_ATE_signed";
-    case DW_ATE_signed_char:
-      return "DW_ATE_signed_char";
-    case DW_ATE_unsigned:
-      return "DW_ATE_unsigned";
-    case DW_ATE_unsigned_char:
-      return "DW_ATE_unsigned_char";
-    default:
-      return "DW_ATE_<unknown>";
+      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_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;
+}
+dw_attr_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;
 }
+die_node;
+
+/* The pubname structure */
+
+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 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;
+
+/* Fixed size portion of the DWARF compilation unit header.  */
+#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 (2 * DWARF_OFFSET_SIZE + 2)
+
+/* Fixed size portion of the address range info.  */
+#define DWARF_ARANGES_HEADER_SIZE \
+  (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE)
+
+/* Define the architecture-dependent minimum instruction length (in bytes).
+   In this implementation of DWARF, this field is used for information
+   purposes only.  Since GCC generates assembly language, we have
+   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
+
+/* Minimum line offset in a special line info. opcode.
+   This value was chosen to give a reasonable range of values.  */
+#define DWARF_LINE_BASE  -10
+
+/* First special line opcde - leave room for the standard opcodes.  */
+#define DWARF_LINE_OPCODE_BASE  10
+
+/* Range of line offsets in a special line info. opcode.  */
+#define DWARF_LINE_RANGE  (254-DWARF_LINE_OPCODE_BASE+1)
+
+/* Flag that indicates the initial value of the is_stmt_start flag.
+   In the present implementation, we do not mark any lines as
+   the beginning of a source statement, because that information
+   is not made available by the GCC front-end.  */
+#define        DWARF_LINE_DEFAULT_IS_STMT_START 1
+
+/* This location is used by calc_die_sizes() to keep track
+   the offset of each DIE within the .debug_info section.  */
+static unsigned long next_die_offset;
+
+/* Record the root of the DIE's built for the current compilation unit.  */
+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;
+
+/* Total number of entries in the table (i.e. array) pointed to by
+   `file_table'.  This is the *total* and includes both used and unused
+   slots.  */
+static unsigned file_table_allocated;
 
-/* Convert a DWARF call frame info. operation to its string name */
+/* Number of entries in the file_table which are actually in use.  */
+static unsigned file_table_in_use;
 
-static char *
-dwarf_cfi_name (cfi_opc)
-     register unsigned cfi_opc;
-{
-  switch (cfi_opc)
-    {
-    case DW_CFA_advance_loc:
-      return "DW_CFA_advance_loc";
-    case DW_CFA_offset:
-      return "DW_CFA_offset";
-    case DW_CFA_restore:
-      return "DW_CFA_restore";
-    case DW_CFA_nop:
-      return "DW_CFA_nop";
-    case DW_CFA_set_loc:
-      return "DW_CFA_set_loc";
-    case DW_CFA_advance_loc1:
-      return "DW_CFA_advance_loc1";
-    case DW_CFA_advance_loc2:
-      return "DW_CFA_advance_loc2";
-    case DW_CFA_advance_loc4:
-      return "DW_CFA_advance_loc4";
-    case DW_CFA_offset_extended:
-      return "DW_CFA_offset_extended";
-    case DW_CFA_restore_extended:
-      return "DW_CFA_restore_extended";
-    case DW_CFA_undefined:
-      return "DW_CFA_undefined";
-    case DW_CFA_same_value:
-      return "DW_CFA_same_value";
-    case DW_CFA_register:
-      return "DW_CFA_register";
-    case DW_CFA_remember_state:
-      return "DW_CFA_remember_state";
-    case DW_CFA_restore_state:
-      return "DW_CFA_restore_state";
-    case DW_CFA_def_cfa:
-      return "DW_CFA_def_cfa";
-    case DW_CFA_def_cfa_register:
-      return "DW_CFA_def_cfa_register";
-    case DW_CFA_def_cfa_offset:
-      return "DW_CFA_def_cfa_offset";
-    /* SGI/MIPS specific */
-    case DW_CFA_MIPS_advance_loc8:
-      return "DW_CFA_MIPS_advance_loc8";
-    default:
-      return "DW_CFA_<unknown>";
-    }
-}
-\f
-/* Determine the "ultimate origin" of a decl.  The decl may be an inlined
-   instance of an inlined instance of a decl which is local to an inline
-   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.  */
+/* Size (in elements) of increments by which we may expand the filename
+   table.  */
+#define FILE_TABLE_INCREMENT 64
 
-static tree
-decl_ultimate_origin (decl)
-     register tree decl;
-{
-  register tree immediate_origin = DECL_ABSTRACT_ORIGIN (decl);
+/* Local pointer to the name of the main input file.  Initialized in
+   dwarf2out_init.  */
+static char *primary_filename;
 
-  if (immediate_origin == NULL_TREE)
-    return NULL_TREE;
-  else
-    {
-      register tree ret_val;
-      register tree lookahead = immediate_origin;
+/* For Dwarf output, we must assign lexical-blocks id numbers in the order in
+   which their beginnings are encountered. We output Dwarf debugging info
+   that refers to the beginnings and ends of the ranges of code for each
+   lexical block.  The labels themselves are generated in final.c, which
+   assigns numbers to the blocks in the same way.  */
+static unsigned next_block_number = 2;
 
-      do
-       {
-         ret_val = lookahead;
-         lookahead = DECL_ABSTRACT_ORIGIN (ret_val);
-       }
-      while (lookahead != NULL && lookahead != ret_val);
+/* 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.  */
+static dw_die_ref *decl_die_table;
 
-      return ret_val;
-    }
-}
+/* Number of elements currently allocated for the decl_die_table.  */
+static unsigned decl_die_table_allocated;
 
-/* Determine the "ultimate origin" of a block.  The block may be an inlined
-   instance of an inlined instance of a block which is local to an inline
-   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.  */
+/* Number of elements in decl_die_table currently in use.  */
+static unsigned decl_die_table_in_use;
 
-static tree
-block_ultimate_origin (block)
-     register tree block;
-{
-  register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
+/* Size (in elements) of increments by which we may expand the
+   decl_die_table.  */
+#define DECL_DIE_TABLE_INCREMENT 256
 
-  if (immediate_origin == NULL_TREE)
-    return NULL_TREE;
-  else
-    {
-      register tree ret_val;
-      register tree lookahead = immediate_origin;
+/* A pointer to the base of a table of references to declaration
+   scopes.  This table is a display which tracks the nesting
+   of declaration scopes at the current scope and containing
+   scopes.  This table is used to find the proper place to
+   define type declaration DIE's.  */
+static tree *decl_scope_table;
 
-      do
-       {
-         ret_val = lookahead;
-         lookahead = (TREE_CODE (ret_val) == BLOCK)
-           ? BLOCK_ABSTRACT_ORIGIN (ret_val)
-           : NULL;
-       }
-      while (lookahead != NULL && lookahead != ret_val);
+/* Number of elements currently allocated for the decl_scope_table.  */
+static unsigned decl_scope_table_allocated;
 
-      return ret_val;
-    }
-}
+/* Current level of nesting of declataion scopes.  */
+static unsigned decl_scope_depth;
 
-/* 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.  */
+/* Size (in elements) of increments by which we may expand the
+   decl_scope_table.  */
+#define DECL_SCOPE_TABLE_INCREMENT 64
 
-static tree
-decl_class_context (decl)
-     tree decl;
-{
-  tree context = NULL_TREE;
+/* A pointer to the base of a list of references to DIE's that
+   are uniquely identified by their tag, presence/absence of
+   children DIE's, and list of attribute/value pairs.  */
+static dw_die_ref *abbrev_die_table;
 
-  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)))));
+/* Number of elements currently allocated for abbrev_die_table.  */
+static unsigned abbrev_die_table_allocated;
 
-  if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't')
-    context = NULL_TREE;
+/* Number of elements in type_die_table currently in use.  */
+static unsigned abbrev_die_table_in_use;
 
-  return context;
-}
-\f
-/* Add an attribute/value pair to a DIE */
+/* Size (in elements) of increments by which we may expand the
+   abbrev_die_table.  */
+#define ABBREV_DIE_TABLE_INCREMENT 256
 
-static inline void
-add_dwarf_attr (die, attr)
-     register dw_die_ref die;
-     register dw_attr_ref attr;
-{
-  if (die != NULL && attr != NULL)
-    {
-      if (die->die_attr == NULL)
-       {
-         die->die_attr = attr;
-         die->die_attr_last = attr;
-       }
-      else
-       {
-         die->die_attr_last->dw_attr_next = attr;
-         die->die_attr_last = attr;
-       }
-    }
-}
+/* A pointer to the base of a table that contains line information
+   for each source code line in .text in the compilation unit.  */
+static dw_line_info_ref line_info_table;
 
-/* Add a flag value attribute to a DIE.  */
+/* Number of elements currently allocated for line_info_table.  */
+static unsigned line_info_table_allocated;
 
-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));
+/* Number of elements in separate_line_info_table currently in use.  */
+static unsigned separate_line_info_table_in_use;
 
-  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);
-}
+/* 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;
 
-/* Add a signed integer attribute value to a DIE.  */
+/* Number of elements currently allocated for separate_line_info_table.  */
+static unsigned separate_line_info_table_allocated;
 
-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));
+/* Number of elements in line_info_table currently in use.  */
+static unsigned line_info_table_in_use;
 
-  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);
-}
+/* Size (in elements) of increments by which we may expand the
+   line_info_table.  */
+#define LINE_INFO_TABLE_INCREMENT 1024
 
-/* Add an unsigned integer attribute value to a DIE.  */
+/* A pointer to the base of a table that contains a list of publicly
+   accessible names.  */
+static pubname_ref pubname_table;
 
-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));
+/* 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;
 
-  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);
-}
+/* Number of elements currently allocated for arange_table.  */
+static unsigned arange_table_allocated;
 
-/* Add an unsigned double integer attribute value to a DIE.  */
+/* Number of elements in arange_table currently in use.  */
+static unsigned arange_table_in_use;
 
-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));
+/* Size (in elements) of increments by which we may expand the
+   arange_table.  */
+#define ARANGE_TABLE_INCREMENT 64
 
-  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);
-}
+/* 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.  */
 
-/* Add a floating point attribute value to a DIE and return it.  */
+static tree *pending_types_list;
 
-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));
+/* Number of elements currently allocated for the pending_types_list.  */
+static unsigned pending_types_allocated;
 
-  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);
-}
+/* Number of elements of pending_types_list currently in use.  */
+static unsigned pending_types;
 
-/* Add a string attribute value to a DIE.  */
+/* 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
 
-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));
+/* Record whether the function being analyzed contains inlined functions.  */
+static int current_function_has_inlines;
+static int comp_unit_has_inlines;
 
-  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);
-}
+/* 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
+   we want to tell the user what the source coordinates for the actual
+   declaration are.  */
+static tree dwarf_last_decl;
 
-/* Add a DIE reference attribute value to a DIE.  */
+/* Forward declarations for functions defined in this file.  */
 
-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));
+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 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 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_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 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 *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 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_label_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 *));
 
-  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);
-}
+/* Section names used to hold DWARF debugging information.  */
+#ifndef DEBUG_SECTION
+#define DEBUG_SECTION          ".debug_info"
+#endif
+#ifndef ABBREV_SECTION
+#define ABBREV_SECTION         ".debug_abbrev"
+#endif
+#ifndef ARANGES_SECTION
+#define ARANGES_SECTION                ".debug_aranges"
+#endif
+#ifndef DW_MACINFO_SECTION
+#define DW_MACINFO_SECTION     ".debug_macinfo"
+#endif
+#ifndef LINE_SECTION
+#define LINE_SECTION           ".debug_line"
+#endif
+#ifndef LOC_SECTION
+#define LOC_SECTION            ".debug_loc"
+#endif
+#ifndef PUBNAMES_SECTION
+#define PUBNAMES_SECTION       ".debug_pubnames"
+#endif
+#ifndef STR_SECTION
+#define STR_SECTION            ".debug_str"
+#endif
 
-/* Add an FDE reference attribute value to a DIE.  */
+/* Standerd ELF section names for compiled code and data.  */
+#ifndef TEXT_SECTION
+#define TEXT_SECTION           ".text"
+#endif
+#ifndef DATA_SECTION
+#define DATA_SECTION           ".data"
+#endif
+#ifndef BSS_SECTION
+#define BSS_SECTION            ".bss"
+#endif
 
-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 = (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_fde_ref;
-  attr->dw_attr_val.v.val_fde_index = targ_fde;
-  add_dwarf_attr (die, attr);
-}
+/* Definitions of defaults for formats and names of various special
+   (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.  */
 
-/* Add a location description attribute value to a DIE.  */
+char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-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));
+#ifndef TEXT_END_LABEL
+#define TEXT_END_LABEL         "Letext"
+#endif
+#ifndef DATA_END_LABEL
+#define DATA_END_LABEL         "Ledata"
+#endif
+#ifndef BSS_END_LABEL
+#define BSS_END_LABEL           "Lebss"
+#endif
+#ifndef INSN_LABEL_FMT
+#define INSN_LABEL_FMT         "LI%u_"
+#endif
+#ifndef BLOCK_BEGIN_LABEL
+#define BLOCK_BEGIN_LABEL      "LBB"
+#endif
+#ifndef BLOCK_END_LABEL
+#define BLOCK_END_LABEL                "LBE"
+#endif
+#ifndef BODY_BEGIN_LABEL
+#define BODY_BEGIN_LABEL       "Lbb"
+#endif
+#ifndef BODY_END_LABEL
+#define BODY_END_LABEL         "Lbe"
+#endif
+#ifndef LINE_CODE_LABEL
+#define LINE_CODE_LABEL                "LM"
+#endif
+#ifndef SEPARATE_LINE_CODE_LABEL
+#define SEPARATE_LINE_CODE_LABEL       "LSM"
+#endif
 
-  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);
-}
+/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
+   newline is produced.  When flag_verbose_asm is asserted, we add commnetary
+   at the end of the line, so we must avoid output of a newline here.  */
+#ifndef ASM_OUTPUT_DWARF_STRING
+#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
+  do {                                                                       \
+    register int slen = strlen(P);                                            \
+    register char *p = (P);                                                  \
+    register int i;                                                          \
+    fprintf (FILE, "\t.ascii \"");                                           \
+    for (i = 0; i < slen; i++)                                               \
+      {                                                                              \
+         register int c = p[i];                                              \
+         if (c == '\"' || c == '\\')                                         \
+           putc ('\\', FILE);                                                \
+         if (c >= ' ' && c < 0177)                                           \
+           putc (c, FILE);                                                   \
+         else                                                                \
+           {                                                                 \
+             fprintf (FILE, "\\%o", c);                                      \
+           }                                                                 \
+      }                                                                              \
+    fprintf (FILE, "\\0\"");                                                 \
+  }                                                                          \
+  while (0)
+#endif
 
-/* Add an address constant attribute value to a DIE.  */
+/* Convert a reference to the assembler name of a C-level name.  This
+   macro has the same effect as ASM_OUTPUT_LABELREF, but copies to
+   a string rather than writing to a file.  */
+#ifndef ASM_NAME_TO_STRING
+#define ASM_NAME_TO_STRING(STR, NAME) \
+  do {                                                                       \
+      if ((NAME)[0] == '*')                                                  \
+       strcpy (STR, NAME+1);                                                 \
+      else                                                                   \
+       strcpy (STR, NAME);                                                   \
+  }                                                                           \
+  while (0)
+#endif
+\f
+/* 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 inline void
-add_AT_addr (die, attr_kind, addr)
-     register dw_die_ref die;
-     register enum dwarf_attribute attr_kind;
-     char *addr;
+static void
+addr_const_to_string (str, x)
+     char *str;
+     rtx x;
 {
-  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_addr;
-  attr->dw_attr_val.v.val_addr = addr;
-  add_dwarf_attr (die, attr);
-}
-
-/* Add a label identifier attribute value to a DIE.  */
+  char buf1[256];
+  char buf2[256];
 
-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));
+restart:
+  str[0] = '\0';
+  switch (GET_CODE (x))
+    {
+    case PC:
+      if (flag_pic)
+       strcat (str, ",");
+      else
+       abort ();
+      break;
 
-  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);
-}
+    case SYMBOL_REF:
+      ASM_NAME_TO_STRING (buf1, XSTR (x, 0));
+      strcat (str, buf1);
+      break;
 
-/* Add a section offset attribute value to a DIE.  */
+    case LABEL_REF:
+      ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
+      ASM_NAME_TO_STRING (buf2, buf1);
+      strcat (str, buf2);
+      break;
 
-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));
+    case CODE_LABEL:
+      ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x));
+      ASM_NAME_TO_STRING (buf2, buf1);
+      strcat (str, buf2);
+      break;
 
-  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);
-  
-}
+    case CONST_INT:
+      sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
+      strcat (str, buf1);
+      break;
 
-/* Test if die refers to an external subroutine.  */
+    case CONST:
+      /* This used to output parentheses around the expression, but that does 
+         not work on the 386 (either ATT or BSD assembler).  */
+      addr_const_to_string (buf1, XEXP (x, 0));
+      strcat (str, buf1);
+      break;
 
-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;
+    case CONST_DOUBLE:
+      if (GET_MODE (x) == VOIDmode)
+       {
+         /* We can use %d if the number is one word and positive.  */
+         if (CONST_DOUBLE_HIGH (x))
+           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, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
+         else
+           sprintf (buf1, HOST_WIDE_INT_PRINT_DEC,
+                    CONST_DOUBLE_LOW (x));
+         strcat (str, buf1);
+       }
+      else
+       /* We can't handle floating point constants; PRINT_OPERAND must
+          handle them.  */
+       output_operand_lossage ("floating constant misused");
+      break;
 
-  if (die != NULL && die->die_tag == DW_TAG_subprogram)
-    {
-      is_subr = TRUE;
-      for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+    case PLUS:
+      /* Some assemblers need integer constants to appear last (eg masm).  */
+      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
        {
-         if (a->dw_attr == DW_AT_external
-             && a->dw_attr_val.val_class == dw_val_class_flag
-             && a->dw_attr_val.v.val_flag != 0)
-           {
-             is_extern = TRUE;
-             break;
-           }
+         addr_const_to_string (buf1, XEXP (x, 1));
+         strcat (str, buf1);
+         if (INTVAL (XEXP (x, 0)) >= 0)
+           strcat (str, "+");
+
+         addr_const_to_string (buf1, XEXP (x, 0));
+         strcat (str, buf1);
        }
-    }
+      else
+       {
+         addr_const_to_string (buf1, XEXP (x, 0));
+         strcat (str, buf1);
+         if (INTVAL (XEXP (x, 1)) >= 0)
+           strcat (str, "+");
 
-  return is_subr && is_extern;
-}
+         addr_const_to_string (buf1, XEXP (x, 1));
+         strcat (str, buf1);
+       }
+      break;
 
-/* Get the attribute of type attr_kind.  */
+    case MINUS:
+      /* Avoid outputting things like x-x or x+5-x, since some assemblers
+         can't handle that.  */
+      x = simplify_subtraction (x);
+      if (GET_CODE (x) != MINUS)
+       goto restart;
 
-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 dw_die_ref spec = NULL;
-  
-  if (die != NULL)
-    {
-      for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+      addr_const_to_string (buf1, XEXP (x, 0));
+      strcat (str, buf1);
+      strcat (str, "-");
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) < 0)
        {
-         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;
+         strcat (str, ASM_OPEN_PAREN);
+         addr_const_to_string (buf1, XEXP (x, 1));
+         strcat (str, buf1);
+         strcat (str, ASM_CLOSE_PAREN);
+       }
+      else
+       {
+         addr_const_to_string (buf1, XEXP (x, 1));
+         strcat (str, buf1);
        }
+      break;
 
-      if (spec)
-       return get_AT (spec, attr_kind);
-    }
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
+      addr_const_to_string (buf1, XEXP (x, 0));
+      strcat (str, buf1);
+      break;
 
-  return NULL;
+    default:
+      output_operand_lossage ("invalid expression as operand");
+    }
 }
 
-/* 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.  */
+/* Convert an address constant to a string, and return a pointer to
+   a copy of the result, located on the heap.  */
 
-static inline char *
-get_AT_low_pc (die)
-     register dw_die_ref die;
+static char *
+addr_to_string (x)
+     rtx x;
 {
-  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;
+  char buf[1024];
+  addr_const_to_string (buf, x);
+  return xstrdup (buf);
 }
 
-/* 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.  */
+/* Test if rtl node points to a psuedo register.  */
 
-static inline char *
-get_AT_hi_pc (die)
-     register dw_die_ref die;
+static inline int
+is_pseudo_reg (rtl)
+     register rtx rtl;
 {
-  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 (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER))
+         || ((GET_CODE (rtl) == SUBREG)
+             && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
 }
 
-/* Return the value of the string attribute designated by ATTR_KIND, or
-   NULL if it is not present.  */
+/* Return a reference to a type, with its const and volatile qualifiers
+   removed.  */
 
-static inline char *
-get_AT_string (die, attr_kind)
-     register dw_die_ref die;
-     register enum dwarf_attribute attr_kind;
+static inline tree
+type_main_variant (type)
+     register tree type;
 {
-  register dw_attr_ref a = get_AT (die, attr_kind);
+  type = TYPE_MAIN_VARIANT (type);
 
-  if (a && a->dw_attr_val.val_class == dw_val_class_str)
-    return a->dw_attr_val.v.val_str;
+  /* There really should be only one main variant among any group of variants 
+     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.  */
 
-  return NULL;
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    while (type != TYPE_MAIN_VARIANT (type))
+      type = TYPE_MAIN_VARIANT (type);
+
+  return type;
 }
 
-/* Return the value of the flag attribute designated by ATTR_KIND, or -1
-   if it is not present.  */
+/* Return non-zero if the given type node represents a tagged type.  */
 
 static inline int
-get_AT_flag (die, attr_kind)
-     register dw_die_ref die;
-     register enum dwarf_attribute attr_kind;
+is_tagged_type (type)
+     register tree type;
 {
-  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;
+  register enum tree_code code = TREE_CODE (type);
 
-  return -1;
+  return (code == RECORD_TYPE || code == UNION_TYPE
+         || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
 }
 
-/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
-   if it is not present.  */
+/* Convert a DIE tag into its string name.  */
 
-static inline unsigned
-get_AT_unsigned (die, attr_kind)
-     register dw_die_ref die;
-     register enum dwarf_attribute attr_kind;
+static char *
+dwarf_tag_name (tag)
+     register unsigned tag;
 {
-  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;
+  switch (tag)
+    {
+    case DW_TAG_padding:
+      return "DW_TAG_padding";
+    case DW_TAG_array_type:
+      return "DW_TAG_array_type";
+    case DW_TAG_class_type:
+      return "DW_TAG_class_type";
+    case DW_TAG_entry_point:
+      return "DW_TAG_entry_point";
+    case DW_TAG_enumeration_type:
+      return "DW_TAG_enumeration_type";
+    case DW_TAG_formal_parameter:
+      return "DW_TAG_formal_parameter";
+    case DW_TAG_imported_declaration:
+      return "DW_TAG_imported_declaration";
+    case DW_TAG_label:
+      return "DW_TAG_label";
+    case DW_TAG_lexical_block:
+      return "DW_TAG_lexical_block";
+    case DW_TAG_member:
+      return "DW_TAG_member";
+    case DW_TAG_pointer_type:
+      return "DW_TAG_pointer_type";
+    case DW_TAG_reference_type:
+      return "DW_TAG_reference_type";
+    case DW_TAG_compile_unit:
+      return "DW_TAG_compile_unit";
+    case DW_TAG_string_type:
+      return "DW_TAG_string_type";
+    case DW_TAG_structure_type:
+      return "DW_TAG_structure_type";
+    case DW_TAG_subroutine_type:
+      return "DW_TAG_subroutine_type";
+    case DW_TAG_typedef:
+      return "DW_TAG_typedef";
+    case DW_TAG_union_type:
+      return "DW_TAG_union_type";
+    case DW_TAG_unspecified_parameters:
+      return "DW_TAG_unspecified_parameters";
+    case DW_TAG_variant:
+      return "DW_TAG_variant";
+    case DW_TAG_common_block:
+      return "DW_TAG_common_block";
+    case DW_TAG_common_inclusion:
+      return "DW_TAG_common_inclusion";
+    case DW_TAG_inheritance:
+      return "DW_TAG_inheritance";
+    case DW_TAG_inlined_subroutine:
+      return "DW_TAG_inlined_subroutine";
+    case DW_TAG_module:
+      return "DW_TAG_module";
+    case DW_TAG_ptr_to_member_type:
+      return "DW_TAG_ptr_to_member_type";
+    case DW_TAG_set_type:
+      return "DW_TAG_set_type";
+    case DW_TAG_subrange_type:
+      return "DW_TAG_subrange_type";
+    case DW_TAG_with_stmt:
+      return "DW_TAG_with_stmt";
+    case DW_TAG_access_declaration:
+      return "DW_TAG_access_declaration";
+    case DW_TAG_base_type:
+      return "DW_TAG_base_type";
+    case DW_TAG_catch_block:
+      return "DW_TAG_catch_block";
+    case DW_TAG_const_type:
+      return "DW_TAG_const_type";
+    case DW_TAG_constant:
+      return "DW_TAG_constant";
+    case DW_TAG_enumerator:
+      return "DW_TAG_enumerator";
+    case DW_TAG_file_type:
+      return "DW_TAG_file_type";
+    case DW_TAG_friend:
+      return "DW_TAG_friend";
+    case DW_TAG_namelist:
+      return "DW_TAG_namelist";
+    case DW_TAG_namelist_item:
+      return "DW_TAG_namelist_item";
+    case DW_TAG_packed_type:
+      return "DW_TAG_packed_type";
+    case DW_TAG_subprogram:
+      return "DW_TAG_subprogram";
+    case DW_TAG_template_type_param:
+      return "DW_TAG_template_type_param";
+    case DW_TAG_template_value_param:
+      return "DW_TAG_template_value_param";
+    case DW_TAG_thrown_type:
+      return "DW_TAG_thrown_type";
+    case DW_TAG_try_block:
+      return "DW_TAG_try_block";
+    case DW_TAG_variant_part:
+      return "DW_TAG_variant_part";
+    case DW_TAG_variable:
+      return "DW_TAG_variable";
+    case DW_TAG_volatile_type:
+      return "DW_TAG_volatile_type";
+    case DW_TAG_MIPS_loop:
+      return "DW_TAG_MIPS_loop";
+    case DW_TAG_format_label:
+      return "DW_TAG_format_label";
+    case DW_TAG_function_template:
+      return "DW_TAG_function_template";
+    case DW_TAG_class_template:
+      return "DW_TAG_class_template";
+    default:
+      return "DW_TAG_<unknown>";
+    }
 }
 
-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.  */
+/* Convert a DWARF attribute code into its string name.  */
 
-static inline void
-remove_AT (die, attr_kind)
-     register dw_die_ref die;
-     register enum dwarf_attribute attr_kind;
+static char *
+dwarf_attr_name (attr)
+     register unsigned attr;
 {
-  register dw_attr_ref a;
-  register dw_attr_ref removed = NULL;;
-
-  if (die != NULL)
+  switch (attr)
     {
-      if (die->die_attr->dw_attr == attr_kind)
-       {
-         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)
-           {
-             removed = a->dw_attr_next;
-             if (die->die_attr_last == a->dw_attr_next)
-               die->die_attr_last = a;
+    case DW_AT_sibling:
+      return "DW_AT_sibling";
+    case DW_AT_location:
+      return "DW_AT_location";
+    case DW_AT_name:
+      return "DW_AT_name";
+    case DW_AT_ordering:
+      return "DW_AT_ordering";
+    case DW_AT_subscr_data:
+      return "DW_AT_subscr_data";
+    case DW_AT_byte_size:
+      return "DW_AT_byte_size";
+    case DW_AT_bit_offset:
+      return "DW_AT_bit_offset";
+    case DW_AT_bit_size:
+      return "DW_AT_bit_size";
+    case DW_AT_element_list:
+      return "DW_AT_element_list";
+    case DW_AT_stmt_list:
+      return "DW_AT_stmt_list";
+    case DW_AT_low_pc:
+      return "DW_AT_low_pc";
+    case DW_AT_high_pc:
+      return "DW_AT_high_pc";
+    case DW_AT_language:
+      return "DW_AT_language";
+    case DW_AT_member:
+      return "DW_AT_member";
+    case DW_AT_discr:
+      return "DW_AT_discr";
+    case DW_AT_discr_value:
+      return "DW_AT_discr_value";
+    case DW_AT_visibility:
+      return "DW_AT_visibility";
+    case DW_AT_import:
+      return "DW_AT_import";
+    case DW_AT_string_length:
+      return "DW_AT_string_length";
+    case DW_AT_common_reference:
+      return "DW_AT_common_reference";
+    case DW_AT_comp_dir:
+      return "DW_AT_comp_dir";
+    case DW_AT_const_value:
+      return "DW_AT_const_value";
+    case DW_AT_containing_type:
+      return "DW_AT_containing_type";
+    case DW_AT_default_value:
+      return "DW_AT_default_value";
+    case DW_AT_inline:
+      return "DW_AT_inline";
+    case DW_AT_is_optional:
+      return "DW_AT_is_optional";
+    case DW_AT_lower_bound:
+      return "DW_AT_lower_bound";
+    case DW_AT_producer:
+      return "DW_AT_producer";
+    case DW_AT_prototyped:
+      return "DW_AT_prototyped";
+    case DW_AT_return_addr:
+      return "DW_AT_return_addr";
+    case DW_AT_start_scope:
+      return "DW_AT_start_scope";
+    case DW_AT_stride_size:
+      return "DW_AT_stride_size";
+    case DW_AT_upper_bound:
+      return "DW_AT_upper_bound";
+    case DW_AT_abstract_origin:
+      return "DW_AT_abstract_origin";
+    case DW_AT_accessibility:
+      return "DW_AT_accessibility";
+    case DW_AT_address_class:
+      return "DW_AT_address_class";
+    case DW_AT_artificial:
+      return "DW_AT_artificial";
+    case DW_AT_base_types:
+      return "DW_AT_base_types";
+    case DW_AT_calling_convention:
+      return "DW_AT_calling_convention";
+    case DW_AT_count:
+      return "DW_AT_count";
+    case DW_AT_data_member_location:
+      return "DW_AT_data_member_location";
+    case DW_AT_decl_column:
+      return "DW_AT_decl_column";
+    case DW_AT_decl_file:
+      return "DW_AT_decl_file";
+    case DW_AT_decl_line:
+      return "DW_AT_decl_line";
+    case DW_AT_declaration:
+      return "DW_AT_declaration";
+    case DW_AT_discr_list:
+      return "DW_AT_discr_list";
+    case DW_AT_encoding:
+      return "DW_AT_encoding";
+    case DW_AT_external:
+      return "DW_AT_external";
+    case DW_AT_frame_base:
+      return "DW_AT_frame_base";
+    case DW_AT_friend:
+      return "DW_AT_friend";
+    case DW_AT_identifier_case:
+      return "DW_AT_identifier_case";
+    case DW_AT_macro_info:
+      return "DW_AT_macro_info";
+    case DW_AT_namelist_items:
+      return "DW_AT_namelist_items";
+    case DW_AT_priority:
+      return "DW_AT_priority";
+    case DW_AT_segment:
+      return "DW_AT_segment";
+    case DW_AT_specification:
+      return "DW_AT_specification";
+    case DW_AT_static_link:
+      return "DW_AT_static_link";
+    case DW_AT_type:
+      return "DW_AT_type";
+    case DW_AT_use_location:
+      return "DW_AT_use_location";
+    case DW_AT_variable_parameter:
+      return "DW_AT_variable_parameter";
+    case DW_AT_virtuality:
+      return "DW_AT_virtuality";
+    case DW_AT_vtable_elem_location:
+      return "DW_AT_vtable_elem_location";
 
-             a->dw_attr_next = a->dw_attr_next->dw_attr_next;
-             break;
-           }
+    case DW_AT_MIPS_fde:
+      return "DW_AT_MIPS_fde";
+    case DW_AT_MIPS_loop_begin:
+      return "DW_AT_MIPS_loop_begin";
+    case DW_AT_MIPS_tail_loop_begin:
+      return "DW_AT_MIPS_tail_loop_begin";
+    case DW_AT_MIPS_epilog_begin:
+      return "DW_AT_MIPS_epilog_begin";
+    case DW_AT_MIPS_loop_unroll_factor:
+      return "DW_AT_MIPS_loop_unroll_factor";
+    case DW_AT_MIPS_software_pipeline_depth:
+      return "DW_AT_MIPS_software_pipeline_depth";
+    case DW_AT_MIPS_linkage_name:
+      return "DW_AT_MIPS_linkage_name";
+    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";
 
-      if (removed != 0)
-       free (removed);
+    case DW_AT_sf_names:
+      return "DW_AT_sf_names";
+    case DW_AT_src_info:
+      return "DW_AT_src_info";
+    case DW_AT_mac_info:
+      return "DW_AT_mac_info";
+    case DW_AT_src_coords:
+      return "DW_AT_src_coords";
+    case DW_AT_body_begin:
+      return "DW_AT_body_begin";
+    case DW_AT_body_end:
+      return "DW_AT_body_end";
+    default:
+      return "DW_AT_<unknown>";
     }
 }
 
-/* Discard the children of this DIE.  */
+/* Convert a DWARF value form code into its string name.  */
 
-static inline void
-remove_children (die)
-     register dw_die_ref die;
+static char *
+dwarf_form_name (form)
+     register unsigned form;
 {
-  register dw_die_ref child_die = die->die_child;
-
-  die->die_child = NULL;
-  die->die_child_last = NULL;
-
-  while (child_die != NULL)
+  switch (form)
     {
-      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);
+    case DW_FORM_addr:
+      return "DW_FORM_addr";
+    case DW_FORM_block2:
+      return "DW_FORM_block2";
+    case DW_FORM_block4:
+      return "DW_FORM_block4";
+    case DW_FORM_data2:
+      return "DW_FORM_data2";
+    case DW_FORM_data4:
+      return "DW_FORM_data4";
+    case DW_FORM_data8:
+      return "DW_FORM_data8";
+    case DW_FORM_string:
+      return "DW_FORM_string";
+    case DW_FORM_block:
+      return "DW_FORM_block";
+    case DW_FORM_block1:
+      return "DW_FORM_block1";
+    case DW_FORM_data1:
+      return "DW_FORM_data1";
+    case DW_FORM_flag:
+      return "DW_FORM_flag";
+    case DW_FORM_sdata:
+      return "DW_FORM_sdata";
+    case DW_FORM_strp:
+      return "DW_FORM_strp";
+    case DW_FORM_udata:
+      return "DW_FORM_udata";
+    case DW_FORM_ref_addr:
+      return "DW_FORM_ref_addr";
+    case DW_FORM_ref1:
+      return "DW_FORM_ref1";
+    case DW_FORM_ref2:
+      return "DW_FORM_ref2";
+    case DW_FORM_ref4:
+      return "DW_FORM_ref4";
+    case DW_FORM_ref8:
+      return "DW_FORM_ref8";
+    case DW_FORM_ref_udata:
+      return "DW_FORM_ref_udata";
+    case DW_FORM_indirect:
+      return "DW_FORM_indirect";
+    default:
+      return "DW_FORM_<unknown>";
     }
 }
 
-/* Add a child DIE below its parent.  */
+/* Convert a DWARF stack opcode into its string name.  */
 
-static inline void
-add_child_die (die, child_die)
-     register dw_die_ref die;
-     register dw_die_ref child_die;
+static char *
+dwarf_stack_op_name (op)
+     register unsigned op;
 {
-  if (die != NULL && child_die != NULL)
+  switch (op)
     {
-      assert (die != child_die);
-      child_die->die_parent = die;
-      child_die->die_sib = NULL;
-
-      if (die->die_child == NULL)
-       {
-         die->die_child = child_die;
-         die->die_child_last = child_die;
-       }
-      else
-       {
-         die->die_child_last->die_sib = child_die;
-         die->die_child_last = child_die;
-       }
+    case DW_OP_addr:
+      return "DW_OP_addr";
+    case DW_OP_deref:
+      return "DW_OP_deref";
+    case DW_OP_const1u:
+      return "DW_OP_const1u";
+    case DW_OP_const1s:
+      return "DW_OP_const1s";
+    case DW_OP_const2u:
+      return "DW_OP_const2u";
+    case DW_OP_const2s:
+      return "DW_OP_const2s";
+    case DW_OP_const4u:
+      return "DW_OP_const4u";
+    case DW_OP_const4s:
+      return "DW_OP_const4s";
+    case DW_OP_const8u:
+      return "DW_OP_const8u";
+    case DW_OP_const8s:
+      return "DW_OP_const8s";
+    case DW_OP_constu:
+      return "DW_OP_constu";
+    case DW_OP_consts:
+      return "DW_OP_consts";
+    case DW_OP_dup:
+      return "DW_OP_dup";
+    case DW_OP_drop:
+      return "DW_OP_drop";
+    case DW_OP_over:
+      return "DW_OP_over";
+    case DW_OP_pick:
+      return "DW_OP_pick";
+    case DW_OP_swap:
+      return "DW_OP_swap";
+    case DW_OP_rot:
+      return "DW_OP_rot";
+    case DW_OP_xderef:
+      return "DW_OP_xderef";
+    case DW_OP_abs:
+      return "DW_OP_abs";
+    case DW_OP_and:
+      return "DW_OP_and";
+    case DW_OP_div:
+      return "DW_OP_div";
+    case DW_OP_minus:
+      return "DW_OP_minus";
+    case DW_OP_mod:
+      return "DW_OP_mod";
+    case DW_OP_mul:
+      return "DW_OP_mul";
+    case DW_OP_neg:
+      return "DW_OP_neg";
+    case DW_OP_not:
+      return "DW_OP_not";
+    case DW_OP_or:
+      return "DW_OP_or";
+    case DW_OP_plus:
+      return "DW_OP_plus";
+    case DW_OP_plus_uconst:
+      return "DW_OP_plus_uconst";
+    case DW_OP_shl:
+      return "DW_OP_shl";
+    case DW_OP_shr:
+      return "DW_OP_shr";
+    case DW_OP_shra:
+      return "DW_OP_shra";
+    case DW_OP_xor:
+      return "DW_OP_xor";
+    case DW_OP_bra:
+      return "DW_OP_bra";
+    case DW_OP_eq:
+      return "DW_OP_eq";
+    case DW_OP_ge:
+      return "DW_OP_ge";
+    case DW_OP_gt:
+      return "DW_OP_gt";
+    case DW_OP_le:
+      return "DW_OP_le";
+    case DW_OP_lt:
+      return "DW_OP_lt";
+    case DW_OP_ne:
+      return "DW_OP_ne";
+    case DW_OP_skip:
+      return "DW_OP_skip";
+    case DW_OP_lit0:
+      return "DW_OP_lit0";
+    case DW_OP_lit1:
+      return "DW_OP_lit1";
+    case DW_OP_lit2:
+      return "DW_OP_lit2";
+    case DW_OP_lit3:
+      return "DW_OP_lit3";
+    case DW_OP_lit4:
+      return "DW_OP_lit4";
+    case DW_OP_lit5:
+      return "DW_OP_lit5";
+    case DW_OP_lit6:
+      return "DW_OP_lit6";
+    case DW_OP_lit7:
+      return "DW_OP_lit7";
+    case DW_OP_lit8:
+      return "DW_OP_lit8";
+    case DW_OP_lit9:
+      return "DW_OP_lit9";
+    case DW_OP_lit10:
+      return "DW_OP_lit10";
+    case DW_OP_lit11:
+      return "DW_OP_lit11";
+    case DW_OP_lit12:
+      return "DW_OP_lit12";
+    case DW_OP_lit13:
+      return "DW_OP_lit13";
+    case DW_OP_lit14:
+      return "DW_OP_lit14";
+    case DW_OP_lit15:
+      return "DW_OP_lit15";
+    case DW_OP_lit16:
+      return "DW_OP_lit16";
+    case DW_OP_lit17:
+      return "DW_OP_lit17";
+    case DW_OP_lit18:
+      return "DW_OP_lit18";
+    case DW_OP_lit19:
+      return "DW_OP_lit19";
+    case DW_OP_lit20:
+      return "DW_OP_lit20";
+    case DW_OP_lit21:
+      return "DW_OP_lit21";
+    case DW_OP_lit22:
+      return "DW_OP_lit22";
+    case DW_OP_lit23:
+      return "DW_OP_lit23";
+    case DW_OP_lit24:
+      return "DW_OP_lit24";
+    case DW_OP_lit25:
+      return "DW_OP_lit25";
+    case DW_OP_lit26:
+      return "DW_OP_lit26";
+    case DW_OP_lit27:
+      return "DW_OP_lit27";
+    case DW_OP_lit28:
+      return "DW_OP_lit28";
+    case DW_OP_lit29:
+      return "DW_OP_lit29";
+    case DW_OP_lit30:
+      return "DW_OP_lit30";
+    case DW_OP_lit31:
+      return "DW_OP_lit31";
+    case DW_OP_reg0:
+      return "DW_OP_reg0";
+    case DW_OP_reg1:
+      return "DW_OP_reg1";
+    case DW_OP_reg2:
+      return "DW_OP_reg2";
+    case DW_OP_reg3:
+      return "DW_OP_reg3";
+    case DW_OP_reg4:
+      return "DW_OP_reg4";
+    case DW_OP_reg5:
+      return "DW_OP_reg5";
+    case DW_OP_reg6:
+      return "DW_OP_reg6";
+    case DW_OP_reg7:
+      return "DW_OP_reg7";
+    case DW_OP_reg8:
+      return "DW_OP_reg8";
+    case DW_OP_reg9:
+      return "DW_OP_reg9";
+    case DW_OP_reg10:
+      return "DW_OP_reg10";
+    case DW_OP_reg11:
+      return "DW_OP_reg11";
+    case DW_OP_reg12:
+      return "DW_OP_reg12";
+    case DW_OP_reg13:
+      return "DW_OP_reg13";
+    case DW_OP_reg14:
+      return "DW_OP_reg14";
+    case DW_OP_reg15:
+      return "DW_OP_reg15";
+    case DW_OP_reg16:
+      return "DW_OP_reg16";
+    case DW_OP_reg17:
+      return "DW_OP_reg17";
+    case DW_OP_reg18:
+      return "DW_OP_reg18";
+    case DW_OP_reg19:
+      return "DW_OP_reg19";
+    case DW_OP_reg20:
+      return "DW_OP_reg20";
+    case DW_OP_reg21:
+      return "DW_OP_reg21";
+    case DW_OP_reg22:
+      return "DW_OP_reg22";
+    case DW_OP_reg23:
+      return "DW_OP_reg23";
+    case DW_OP_reg24:
+      return "DW_OP_reg24";
+    case DW_OP_reg25:
+      return "DW_OP_reg25";
+    case DW_OP_reg26:
+      return "DW_OP_reg26";
+    case DW_OP_reg27:
+      return "DW_OP_reg27";
+    case DW_OP_reg28:
+      return "DW_OP_reg28";
+    case DW_OP_reg29:
+      return "DW_OP_reg29";
+    case DW_OP_reg30:
+      return "DW_OP_reg30";
+    case DW_OP_reg31:
+      return "DW_OP_reg31";
+    case DW_OP_breg0:
+      return "DW_OP_breg0";
+    case DW_OP_breg1:
+      return "DW_OP_breg1";
+    case DW_OP_breg2:
+      return "DW_OP_breg2";
+    case DW_OP_breg3:
+      return "DW_OP_breg3";
+    case DW_OP_breg4:
+      return "DW_OP_breg4";
+    case DW_OP_breg5:
+      return "DW_OP_breg5";
+    case DW_OP_breg6:
+      return "DW_OP_breg6";
+    case DW_OP_breg7:
+      return "DW_OP_breg7";
+    case DW_OP_breg8:
+      return "DW_OP_breg8";
+    case DW_OP_breg9:
+      return "DW_OP_breg9";
+    case DW_OP_breg10:
+      return "DW_OP_breg10";
+    case DW_OP_breg11:
+      return "DW_OP_breg11";
+    case DW_OP_breg12:
+      return "DW_OP_breg12";
+    case DW_OP_breg13:
+      return "DW_OP_breg13";
+    case DW_OP_breg14:
+      return "DW_OP_breg14";
+    case DW_OP_breg15:
+      return "DW_OP_breg15";
+    case DW_OP_breg16:
+      return "DW_OP_breg16";
+    case DW_OP_breg17:
+      return "DW_OP_breg17";
+    case DW_OP_breg18:
+      return "DW_OP_breg18";
+    case DW_OP_breg19:
+      return "DW_OP_breg19";
+    case DW_OP_breg20:
+      return "DW_OP_breg20";
+    case DW_OP_breg21:
+      return "DW_OP_breg21";
+    case DW_OP_breg22:
+      return "DW_OP_breg22";
+    case DW_OP_breg23:
+      return "DW_OP_breg23";
+    case DW_OP_breg24:
+      return "DW_OP_breg24";
+    case DW_OP_breg25:
+      return "DW_OP_breg25";
+    case DW_OP_breg26:
+      return "DW_OP_breg26";
+    case DW_OP_breg27:
+      return "DW_OP_breg27";
+    case DW_OP_breg28:
+      return "DW_OP_breg28";
+    case DW_OP_breg29:
+      return "DW_OP_breg29";
+    case DW_OP_breg30:
+      return "DW_OP_breg30";
+    case DW_OP_breg31:
+      return "DW_OP_breg31";
+    case DW_OP_regx:
+      return "DW_OP_regx";
+    case DW_OP_fbreg:
+      return "DW_OP_fbreg";
+    case DW_OP_bregx:
+      return "DW_OP_bregx";
+    case DW_OP_piece:
+      return "DW_OP_piece";
+    case DW_OP_deref_size:
+      return "DW_OP_deref_size";
+    case DW_OP_xderef_size:
+      return "DW_OP_xderef_size";
+    case DW_OP_nop:
+      return "DW_OP_nop";
+    default:
+      return "OP_<unknown>";
     }
 }
 
-/* Return a pointer to a newly created DIE node.  */
-
-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));
-
-  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.  */
-
-static inline dw_die_ref
-lookup_type_die (type)
-     register tree type;
-{
-  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;
-{
-  TYPE_SYMTAB_POINTER (type) = (char *) type_die;
-}
-
-/* Return the DIE associated with a given declaration.  */
-
-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);
-}
-
-/* Equate a DIE to a particular declaration.  */
+/* Convert a DWARF type code into its string name.  */
 
-static void
-equate_decl_number_to_die (decl, decl_die)
-     register tree decl;
-     register dw_die_ref decl_die;
+static char *
+dwarf_type_encoding_name (enc)
+     register unsigned enc;
 {
-  register unsigned decl_id = DECL_UID (decl);
-  register unsigned i;
-  register unsigned num_allocated;
-
-  if (decl_id >= decl_die_table_allocated)
+  switch (enc)
     {
-      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[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.  */
-
-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));
-
-  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;
+    case DW_ATE_address:
+      return "DW_ATE_address";
+    case DW_ATE_boolean:
+      return "DW_ATE_boolean";
+    case DW_ATE_complex_float:
+      return "DW_ATE_complex_float";
+    case DW_ATE_float:
+      return "DW_ATE_float";
+    case DW_ATE_signed:
+      return "DW_ATE_signed";
+    case DW_ATE_signed_char:
+      return "DW_ATE_signed_char";
+    case DW_ATE_unsigned:
+      return "DW_ATE_unsigned";
+    case DW_ATE_unsigned_char:
+      return "DW_ATE_unsigned_char";
+    default:
+      return "DW_ATE_<unknown>";
+    }
 }
+\f
+/* Determine the "ultimate origin" of a decl.  The decl may be an inlined
+   instance of an inlined instance of a decl which is local to an inline
+   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.  */
 
-/* Add a location description term to a location description expression.  */
-
-static inline void
-add_loc_descr (list_head, descr)
-     register dw_loc_descr_ref *list_head;
-     register dw_loc_descr_ref descr;
+static tree
+decl_ultimate_origin (decl)
+     register tree decl;
 {
-  register dw_loc_descr_ref *d;
+  register tree immediate_origin = DECL_ABSTRACT_ORIGIN (decl);
 
-  /* Find the end of the chain.  */
-  for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
-    ;
+  if (immediate_origin == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      register tree ret_val;
+      register tree lookahead = immediate_origin;
 
-  *d = descr;
+      do
+       {
+         ret_val = lookahead;
+         lookahead = DECL_ABSTRACT_ORIGIN (ret_val);
+       }
+      while (lookahead != NULL && lookahead != ret_val);
+
+      return ret_val;
+    }
 }
 
-/* Return a pointer to a newly allocated Call Frame Instruction.  */
+/* Determine the "ultimate origin" of a block.  The block may be an inlined
+   instance of an inlined instance of a block which is local to an inline
+   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 inline dw_cfi_ref
-new_cfi ()
+static tree
+block_ultimate_origin (block)
+     register tree block;
 {
-  register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node));
+  register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
 
-  cfi->dw_cfi_next = NULL;
-  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
-  cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
+  if (immediate_origin == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      register tree ret_val;
+      register tree lookahead = immediate_origin;
 
-  return cfi;
+      do
+       {
+         ret_val = lookahead;
+         lookahead = (TREE_CODE (ret_val) == BLOCK)
+           ? BLOCK_ABSTRACT_ORIGIN (ret_val)
+           : NULL;
+       }
+      while (lookahead != NULL && lookahead != ret_val);
+
+      return ret_val;
+    }
 }
 
-/* Add a Call Frame Instruction to list of instructions.  */
+/* 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 inline void
-add_cfi (list_head, cfi)
-     register dw_cfi_ref *list_head;
-     register dw_cfi_ref cfi;
+static tree
+decl_class_context (decl)
+     tree decl;
 {
-  register dw_cfi_ref *p;
+  tree context = NULL_TREE;
 
-  /* Find the end of the chain.  */
-  for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
-    ;
+  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)))));
 
-  *p = cfi;
+  if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't')
+    context = NULL_TREE;
+
+  return context;
 }
 \f
-/* 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.  */
+/* Add an attribute/value pair to a DIE */
 
 static inline void
-print_spaces (outfile)
-     FILE *outfile;
-{
-  fprintf (outfile, "%*s", print_indent, "");
-}
-
-/* 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;
-     FILE *outfile;
+add_dwarf_attr (die, attr)
+     register dw_die_ref die;
+     register dw_attr_ref attr;
 {
-  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)
+  if (die != NULL && attr != NULL)
     {
-      print_spaces (outfile);
-      fprintf (outfile, "  %s: ", dwarf_attr_name (a->dw_attr));
-
-      switch (a->dw_attr_val.val_class)
+      if (die->die_attr == NULL)
        {
-       case dw_val_class_addr:
-         fprintf (outfile, "address");
-         break;
-       case dw_val_class_loc:
-         fprintf (outfile, "location descriptor");
-         break;
-       case dw_val_class_const:
-         fprintf (outfile, "%d", a->dw_attr_val.v.val_int);
-         break;
-       case dw_val_class_unsigned_const:
-         fprintf (outfile, "%u", a->dw_attr_val.v.val_unsigned);
-         break;
-       case dw_val_class_long_long:
-         fprintf (outfile, "constant (%u,%u)",
-                 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);
-         else
-           fprintf (outfile, "die -> <null>");
-         break;
-       case dw_val_class_lbl_id:
-         fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id);
-         break;
-       case dw_val_class_section_offset:
-         fprintf (outfile, "section: %s", a->dw_attr_val.v.val_section);
-         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);
-         else
-           fprintf (outfile, "<null>");
-         break;
+         die->die_attr = attr;
+         die->die_attr_last = attr;
+       }
+      else
+       {
+         die->die_attr_last->dw_attr_next = attr;
+         die->die_attr_last = attr;
        }
-
-      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_indent -= 4;
     }
 }
 
-/* Print the contents of the source code line number correspondence table.
-   This routine is a debugging aid only.  */
+/* Add a flag value attribute to a DIE.  */
 
-static void
-print_dwarf_line_table (outfile)
-     FILE *outfile;
+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 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)
-    {
-      line_info = &line_info_table[i];
-      fprintf (outfile, "%5d: ", i);
-      fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]);
-      fprintf (outfile, "%6d", line_info->dw_line_num);
-      fprintf (outfile, "\n");
-    }
+  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
 
-  fprintf (outfile, "\n\n");
+  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);
 }
 
-/* Print the information collected for a given DIE.  */
+/* Add a signed integer attribute value to a DIE.  */
 
-void
-debug_dwarf_die (die)
-     dw_die_ref die;
+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;
 {
-  print_die (die, stderr);
+  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_const;
+  attr->dw_attr_val.v.val_int = int_val;
+  add_dwarf_attr (die, attr);
 }
 
-/* Print all DWARF information collected for the compilation unit.
-   This routine is a debugging aid only.  */
+/* Add an unsigned integer attribute value to a DIE.  */
 
-void
-debug_dwarf ()
+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;
 {
-  print_indent = 0;
-  print_die (comp_unit_die, stderr);
-  print_dwarf_line_table (stderr);
+  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_unsigned_const;
+  attr->dw_attr_val.v.val_unsigned = unsigned_val;
+  add_dwarf_attr (die, attr);
 }
-\f
-/* 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)
+/* Add an unsigned double integer attribute value to a DIE.  */
+
+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_die_ref c;
-  register dw_attr_ref attr;
-  if (die != comp_unit_die && die->die_child != NULL)
-    {
-      attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
-      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;
+  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
 
-      /* 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;
+  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);
+}
 
-      die->die_attr = attr;
-    }
+/* Add a floating point attribute value to a DIE and return it.  */
 
-  for (c = die->die_child; c != NULL; c = c->die_sib)
-    add_sibling_attributes (c);
+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);
 }
 
-/* The format of each DIE (and its attribute value pairs)
-   is encoded in an abbreviation table.  This routine builds the
-   abbreviation table and assigns a unique abbreviation id for
-   each abbreviation entry.  The children of each die are visited
-   recursively.  */
+/* Add a string attribute value to a DIE.  */
 
-static void
-build_abbrev_table (die)
+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 unsigned long abbrev_id;
-  register unsigned long n_alloc;
-  register dw_die_ref c;
-  register dw_attr_ref d_attr, 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];
-
-      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;
+  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
 
-             while (a_attr != NULL && d_attr != NULL)
-               {
-                 if ((a_attr->dw_attr != d_attr->dw_attr)
-                     || (value_format (&a_attr->dw_attr_val)
-                         != value_format (&d_attr->dw_attr_val)))
-                   break;
+  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);
+}
 
-                 a_attr = a_attr->dw_attr_next;
-                 d_attr = d_attr->dw_attr_next;
-               }
+/* Add a DIE reference attribute value to a DIE.  */
 
-             if (a_attr == NULL && d_attr == NULL)
-               break;
-           }
-       }
-    }
+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 (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);
+  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);
+}
 
-         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;
-       }
+/* Add an FDE reference attribute value to a DIE.  */
 
-      ++abbrev_die_table_in_use;
-      abbrev_die_table[abbrev_id] = die;
-    }
+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 = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
 
-  die->die_abbrev = abbrev_id;
-  for (c = die->die_child; c != NULL; c = c->die_sib)
-    build_abbrev_table (c);
+  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);
 }
-\f
-/* Return the size of an unsigned LEB128 quantity.  */
 
-static inline unsigned long
-size_of_uleb128 (value)
-     register unsigned long value;
-{
-  register unsigned long size = 0;
-  register unsigned byte;
+/* Add a location description attribute value to a DIE.  */
 
-  do
-    {
-      byte = (value & 0x7f);
-      value >>= 7;
-      size += 1;
-    }
-  while (value != 0);
+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));
 
-  return size;
+  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);
 }
 
-/* Return the size of a signed LEB128 quantity.  */
+/* Add an address constant attribute value to a DIE.  */
 
-static inline unsigned long
-size_of_sleb128 (value)
-     register long value;
+static inline void
+add_AT_addr (die, attr_kind, addr)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
+     char *addr;
 {
-  register unsigned long size = 0;
-  register unsigned byte;
-
-  do
-    {
-      byte = (value & 0x7f);
-      value >>= 7;
-      size += 1;
-    }
-  while (!(((value == 0) && ((byte & 0x40) == 0))
-          || ((value == -1) && ((byte & 0x40) != 0))));
+  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
 
-  return size;
+  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);
 }
 
-/* Return the size of a string, including the null byte.  */
+/* Add a label identifier attribute value to a DIE.  */
 
-static unsigned long
-size_of_string (str)
-     register char *str;
+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 unsigned long size = 0;
-  register unsigned long slen = strlen (str);
-  register unsigned long i;
-  register unsigned c;
+  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
 
-  for (i = 0; i < slen; ++i)
-    {
-      c = str[i];
-      if (c == '\\')
-       ++i;
+  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);
+}
 
-      size += 1;
-    }
+/* Add a section offset attribute value to a DIE.  */
+
+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));
 
-  /* Null terminator.  */
-  size += 1;
-  return size;
+  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);
+  
 }
 
-/* Return the size of a location descriptor.  */
+/* Test if die refers to an external subroutine.  */
 
-static unsigned long
-size_of_loc_descr (loc)
-     register dw_loc_descr_ref loc;
+static inline int
+is_extern_subr_die (die)
+     register dw_die_ref die;
 {
-  register unsigned long size = 1;
+  register dw_attr_ref a;
+  register int is_subr = FALSE;
+  register int is_extern = FALSE;
 
-  switch (loc->dw_loc_opc)
+  if (die != NULL && die->die_tag == DW_TAG_subprogram)
     {
-    case DW_OP_addr:
-      size += PTR_SIZE;
-      break;
-    case DW_OP_const1u:
-    case DW_OP_const1s:
-      size += 1;
-      break;
-    case DW_OP_const2u:
-    case DW_OP_const2s:
-      size += 2;
-      break;
-    case DW_OP_const4u:
-    case DW_OP_const4s:
-      size += 4;
-      break;
-    case DW_OP_const8u:
-    case DW_OP_const8s:
-      size += 8;
-      break;
-    case DW_OP_constu:
-      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
-      break;
-    case DW_OP_consts:
-      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
-      break;
-    case DW_OP_pick:
-      size += 1;
-      break;
-    case DW_OP_plus_uconst:
-      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
-      break;
-    case DW_OP_skip:
-    case DW_OP_bra:
-      size += 2;
-      break;
-    case DW_OP_breg0:
-    case DW_OP_breg1:
-    case DW_OP_breg2:
-    case DW_OP_breg3:
-    case DW_OP_breg4:
-    case DW_OP_breg5:
-    case DW_OP_breg6:
-    case DW_OP_breg7:
-    case DW_OP_breg8:
-    case DW_OP_breg9:
-    case DW_OP_breg10:
-    case DW_OP_breg11:
-    case DW_OP_breg12:
-    case DW_OP_breg13:
-    case DW_OP_breg14:
-    case DW_OP_breg15:
-    case DW_OP_breg16:
-    case DW_OP_breg17:
-    case DW_OP_breg18:
-    case DW_OP_breg19:
-    case DW_OP_breg20:
-    case DW_OP_breg21:
-    case DW_OP_breg22:
-    case DW_OP_breg23:
-    case DW_OP_breg24:
-    case DW_OP_breg25:
-    case DW_OP_breg26:
-    case DW_OP_breg27:
-    case DW_OP_breg28:
-    case DW_OP_breg29:
-    case DW_OP_breg30:
-    case DW_OP_breg31:
-      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
-      break;
-    case DW_OP_regx:
-      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
-      break;
-    case DW_OP_fbreg:
-      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
-      break;
-    case DW_OP_bregx:
-      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
-      size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
-      break;
-    case DW_OP_piece:
-      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
-      break;
-    case DW_OP_deref_size:
-    case DW_OP_xderef_size:
-      size += 1;
-      break;
-    default:
-      break;
+      is_subr = TRUE;
+      for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+       {
+         if (a->dw_attr == DW_AT_external
+             && a->dw_attr_val.val_class == dw_val_class_flag
+             && a->dw_attr_val.v.val_flag != 0)
+           {
+             is_extern = TRUE;
+             break;
+           }
+       }
     }
 
-  return size;
+  return is_subr && is_extern;
 }
 
-/* Return the size of a series of location descriptors.  */
+/* Get the attribute of type attr_kind.  */
 
-static unsigned long
-size_of_locs (loc)
-     register dw_loc_descr_ref loc;
+static inline dw_attr_ref
+get_AT (die, attr_kind)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
 {
-  register unsigned long size = 0;
+  register dw_attr_ref a;
+  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 == attr_kind)
+           return a;
 
-  for (; loc != NULL; loc = loc->dw_loc_next)
-    size += size_of_loc_descr (loc);
+         if (a->dw_attr == DW_AT_specification
+             || a->dw_attr == DW_AT_abstract_origin)
+           spec = a->dw_attr_val.v.val_die_ref;
+       }
 
-  return size;
+      if (spec)
+       return get_AT (spec, attr_kind);
+    }
+
+  return NULL;
 }
 
-/* Return the power-of-two number of bytes necessary to represent VALUE.  */
+/* 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 int
-constant_size (value)
-     long unsigned value;
+static inline char *
+get_AT_low_pc (die)
+     register dw_die_ref die;
 {
-  int log;
-
-  if (value == 0)
-    log = 0;
-  else
-    log = floor_log2 (value);
+  register dw_attr_ref a = get_AT (die, DW_AT_low_pc);
 
-  log = log / 8;
-  log = 1 << (floor_log2 (log) + 1);
+  if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
+    return a->dw_attr_val.v.val_lbl_id;
 
-  return log;
+  return NULL;
 }
 
-/* Return the size of a DIE, as it is represented in the
-   .debug_info section.  */
+/* 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.  */
 
-static unsigned long
-size_of_die (die)
+static inline char *
+get_AT_hi_pc (die)
      register dw_die_ref die;
 {
-  register unsigned long size = 0;
-  register dw_attr_ref a;
+  register dw_attr_ref a = get_AT (die, DW_AT_high_pc);
 
-  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 += PTR_SIZE;
-         break;
-       case dw_val_class_loc:
-         {
-           register unsigned long lsize
-             = size_of_locs (a->dw_attr_val.v.val_loc);
+  if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
+    return a->dw_attr_val.v.val_lbl_id;
 
-           /* Block length.  */
-           size += constant_size (lsize);
-           size += lsize;
-         }
-         break;
-       case dw_val_class_const:
-         size += 4;
-         break;
-       case dw_val_class_unsigned_const:
-         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_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 += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_fde_ref:
-         size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_lbl_id:
-         size += PTR_SIZE;
-         break;
-       case dw_val_class_section_offset:
-         size += DWARF_OFFSET_SIZE;
-         break;
-       case dw_val_class_str:
-         size += size_of_string (a->dw_attr_val.v.val_str);
-         break;
-       default:
-         abort ();
-       }
-    }
+  return NULL;
+}
+
+/* Return the value of the string attribute designated by ATTR_KIND, or
+   NULL if it is not present.  */
 
-  return size;
+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;
 }
 
-/* Size the debgging information associted with a given DIE.
-   Visits the DIE's children recursively.  Updates the global
-   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.  */
+/* Return the value of the flag attribute designated by ATTR_KIND, or -1
+   if it is not present.  */
 
-static void
-calc_die_sizes (die)
-     dw_die_ref die;
+static inline int
+get_AT_flag (die, attr_kind)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
 {
-  register dw_die_ref c;
-  die->die_offset = next_die_offset;
-  next_die_offset += size_of_die (die);
+  register dw_attr_ref a = get_AT (die, attr_kind);
 
-  for (c = die->die_child; c != NULL; c = c->die_sib)
-    calc_die_sizes (c);
+  if (a && a->dw_attr_val.val_class == dw_val_class_flag)
+    return a->dw_attr_val.v.val_flag;
 
-  if (die->die_child != NULL)
-    /* Count the null byte used to terminate sibling lists.  */
-    next_die_offset += 1;
+  return -1;
 }
 
-/* Return the size of the line information prolog generated for the
-   compilation unit.  */
+/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
+   if it is not present.  */
 
-static unsigned long
-size_of_line_prolog ()
+static inline unsigned
+get_AT_unsigned (die, attr_kind)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
 {
-  register unsigned long size;
-  register unsigned long ft_index;
+  register dw_attr_ref a = get_AT (die, attr_kind);
 
-  size = DWARF_LINE_PROLOG_HEADER_SIZE;
+  if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const)
+    return a->dw_attr_val.v.val_unsigned;
 
-  /* Count the size of the table giving number of args for each
-     standard opcode.  */
-  size += DWARF_LINE_OPCODE_BASE - 1;
+  return 0;
+}
 
-  /* Include directory table is empty (at present).  Count only the
-     the null byte used to terminate the table.  */
-  size += 1;
+static inline int
+is_c_family ()
+{
+  register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
 
-  for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
-    {
-      /* File name entry.  */
-      size += size_of_string (file_table[ft_index]);
+  return (lang == DW_LANG_C || lang == DW_LANG_C89
+         || lang == DW_LANG_C_plus_plus);
+} 
 
-      /* Include directory index.  */
-      size += size_of_uleb128 (0);
+static inline int
+is_fortran ()
+{
+  register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
 
-      /* Modification time.  */
-      size += size_of_uleb128 (0);
+  return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90);
+} 
 
-      /* File length in bytes.  */
-      size += size_of_uleb128 (0);
-    }
+/* Remove the specified attribute if present.  */
 
-  /* Count the file table terminator.  */
-  size += 1;
-  return size;
-}
+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 dw_attr_ref removed = NULL;;
 
-/* Return the size of the line information generated for this
-   compilation unit.  */
+  if (die != NULL)
+    {
+      if (die->die_attr->dw_attr == attr_kind)
+       {
+         removed = die->die_attr;
+         if (die->die_attr_last == die->die_attr)
+           die->die_attr_last = NULL;
 
-static unsigned long
-size_of_line_info ()
-{
-  register unsigned long size;
-  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;
+         die->die_attr = die->die_attr->dw_attr_next;
+       }
 
-  /* Version number.  */
-  size = 2;
+      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)
+           {
+             removed = a->dw_attr_next;
+             if (die->die_attr_last == a->dw_attr_next)
+               die->die_attr_last = a;
 
-  /* Prolog length specifier.  */
-  size += DWARF_OFFSET_SIZE;
+             a->dw_attr_next = a->dw_attr_next->dw_attr_next;
+             break;
+           }
 
-  /* Prolog.  */
-  size += size_of_line_prolog ();
+      if (removed != 0)
+       free (removed);
+    }
+}
 
-  /* Set address register instruction.  */
-  size += 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE;
+/* Discard the children of this DIE.  */
 
-  current_file = 1;
-  current_line = 1;
-  for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
+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_line_info_ref line_info;
+      register dw_die_ref tmp_die = child_die;
+      register dw_attr_ref a;
 
-      /* Advance pc instruction.  */
-      size += 1 + 2;
-      line_info = &line_info_table[lt_index];
-      if (line_info->dw_file_num != current_file)
+      child_die = child_die->die_sib;
+      
+      for (a = tmp_die->die_attr; a != NULL; )
        {
-         /* Set file number instruction.  */
-         size += 1;
-         current_file = line_info->dw_file_num;
-         size += size_of_uleb128 (current_file);
-       }
+         register dw_attr_ref tmp_a = a;
 
-      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;
-           }
+         a = a->dw_attr_next;
+         free (tmp_a);
        }
-    }
 
-  /* Advance pc instruction.  */
-  size += 1 + 2;
+      free (tmp_die);
+    }
+}
 
-  /* End of line number info. marker.  */
-  size += 1 + size_of_uleb128 (1) + 1;
+/* Add a child DIE below its parent.  */
 
-  function = 0;
-  current_file = 1;
-  current_line = 1;
-  for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
+static inline void
+add_child_die (die, child_die)
+     register dw_die_ref die;
+     register dw_die_ref child_die;
+{
+  if (die != NULL && child_die != NULL)
     {
-      register dw_separate_line_info_ref line_info
-       = &separate_line_info_table[lt_index];
-      if (function != line_info->function)
+      assert (die != child_die);
+      child_die->die_parent = die;
+      child_die->die_sib = NULL;
+
+      if (die->die_child == NULL)
        {
-         function = line_info->function;
-         /* Set address register instruction.  */
-         size += 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE;
+         die->die_child = child_die;
+         die->die_child_last = child_die;
        }
       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);
+         die->die_child_last->die_sib = child_die;
+         die->die_child_last = child_die;
        }
+    }
+}
+
+/* Return a pointer to a newly created DIE node.  */
+
+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));
+
+  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;
 
-      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);
+  return die;
+}
 
-             /* Generate line entry instruction.  */
-             size += 1;
-           }
-       }
+/* Return the DIE associated with the given type specifier.  */
 
-      ++lt_index;
+static inline dw_die_ref
+lookup_type_die (type)
+     register tree type;
+{
+  return (dw_die_ref) TYPE_SYMTAB_POINTER (type);
+}
 
-      /* 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;
+/* Equate a DIE to a given type specifier.  */
 
-         /* Advance pc instruction.  */
-         size += 1 + 2;
+static void
+equate_type_number_to_die (type, type_die)
+     register tree type;
+     register dw_die_ref type_die;
+{
+  TYPE_SYMTAB_POINTER (type) = (char *) type_die;
+}
 
-         /* End of line number info. marker.  */
-         size += 1 + size_of_uleb128 (1) + 1;
-       }
-    }
+/* Return the DIE associated with a given declaration.  */
 
-  return size;
+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 the size of the .debug_pubnames table  generated for the
-   compilation unit.  */
+/* Equate a DIE to a particular declaration.  */
 
-static unsigned long
-size_of_pubnames ()
+static void
+equate_decl_number_to_die (decl, decl_die)
+     register tree decl;
+     register dw_die_ref decl_die;
 {
-  register unsigned long size;
+  register unsigned decl_id = DECL_UID (decl);
   register unsigned i;
+  register unsigned num_allocated;
 
-  size = DWARF_PUBNAMES_HEADER_SIZE;
-  for (i = 0; i < pubname_table_in_use; ++i)
+  if (decl_id >= decl_die_table_allocated)
     {
-      register pubname_ref p = &pubname_table[i];
-      size += DWARF_OFFSET_SIZE + size_of_string (p->name);
+      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;
     }
 
-  size += DWARF_OFFSET_SIZE;
-  return size;
+  if (decl_id >= decl_die_table_in_use)
+    decl_die_table_in_use = (decl_id + 1);
+
+  decl_die_table[decl_id] = decl_die;
 }
 
-/* Return the size of the information in the .debug_aranges seciton.  */
+/* 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.  */
 
-static unsigned long
-size_of_aranges ()
+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 unsigned long size;
-
-  size = DWARF_ARANGES_HEADER_SIZE;
+  register dw_loc_descr_ref descr
+    = (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node));
 
-  /* Count the address/length pair for this compilation unit.  */
-  size += 2 * PTR_SIZE;
-  size += 2 * PTR_SIZE * arange_table_in_use;
+  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;
 
-  /* Count the two zero words used to terminated the address range table.  */
-  size += 2 * PTR_SIZE;
-  return size;
+  return descr;
 }
-\f
-/* Output an unsigned LEB128 quantity.  */
 
-static void
-output_uleb128 (value)
-     register unsigned long value;
+/* Add a location description term to a location description expression.  */
+
+static inline void
+add_loc_descr (list_head, descr)
+     register dw_loc_descr_ref *list_head;
+     register dw_loc_descr_ref descr;
 {
-  unsigned long save_value = value;
+  register dw_loc_descr_ref *d;
 
-  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;
+  /* Find the end of the chain.  */
+  for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
+    ;
 
-      fprintf (asm_out_file, "0x%x", byte);
-      if (value != 0)
-       fprintf (asm_out_file, ",");
-    }
-  while (value != 0);
+  *d = descr;
+}
+\f
+/* 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;
 
-  if (flag_verbose_asm)
-    fprintf (asm_out_file, "\t%s ULEB128 0x%x", ASM_COMMENT_START, save_value);
+/* Indent the line the number of spaces given by print_indent.  */
+
+static inline void
+print_spaces (outfile)
+     FILE *outfile;
+{
+  fprintf (outfile, "%*s", print_indent, "");
 }
 
-/* Output an signed LEB128 quantity.  */
+/* Print the information assoaciated with a given DIE, and its children.
+   This routine is a debugging aid only.  */
 
 static void
-output_sleb128 (value)
-     register long value;
+print_die (die, outfile)
+     dw_die_ref die;
+     FILE *outfile;
 {
-  register int more;
-  register unsigned byte;
-  long save_value = value;
+  register dw_attr_ref a;
+  register dw_die_ref c;
 
-  fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
-  do
+  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)
     {
-      byte = (value & 0x7f);
-      /* arithmetic shift */
-      value >>= 7;
-      more = !((((value == 0) && ((byte & 0x40) == 0))
-               || ((value == -1) && ((byte & 0x40) != 0))));
-      if (more)
-       byte |= 0x80;
+      print_spaces (outfile);
+      fprintf (outfile, "  %s: ", dwarf_attr_name (a->dw_attr));
+
+      switch (a->dw_attr_val.val_class)
+       {
+       case dw_val_class_addr:
+         fprintf (outfile, "address");
+         break;
+       case dw_val_class_loc:
+         fprintf (outfile, "location descriptor");
+         break;
+       case dw_val_class_const:
+         fprintf (outfile, "%d", a->dw_attr_val.v.val_int);
+         break;
+       case dw_val_class_unsigned_const:
+         fprintf (outfile, "%u", a->dw_attr_val.v.val_unsigned);
+         break;
+       case dw_val_class_long_long:
+         fprintf (outfile, "constant (%u,%u)",
+                 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);
+         else
+           fprintf (outfile, "die -> <null>");
+         break;
+       case dw_val_class_lbl_id:
+         fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id);
+         break;
+       case dw_val_class_section_offset:
+         fprintf (outfile, "section: %s", a->dw_attr_val.v.val_section);
+         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);
+         else
+           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);
 
-      fprintf (asm_out_file, "0x%x", byte);
-      if (more)
-       fprintf (asm_out_file, ",");
+      print_indent -= 4;
     }
-
-  while (more);
-  if (flag_verbose_asm)
-    fprintf (asm_out_file, "\t%s SLEB128 %d", ASM_COMMENT_START, save_value);
 }
 
-/* Select the encoding of an attribute value.  */
+/* Print the contents of the source code line number correspondence table.
+   This routine is a debugging aid only.  */
 
-static enum dwarf_form
-value_format (v)
-     dw_val_ref v;
+static void
+print_dwarf_line_table (outfile)
+     FILE *outfile;
 {
-  switch (v->val_class)
+  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)
     {
-    case dw_val_class_addr:
-      return DW_FORM_addr;
-    case dw_val_class_loc:
-      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:
-      return DW_FORM_data4;
-    case dw_val_class_unsigned_const:
-      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:
-      return DW_FORM_flag;
-    case dw_val_class_die_ref:
-      return DW_FORM_ref;
-    case dw_val_class_fde_ref:
-      return DW_FORM_data;
-    case dw_val_class_lbl_id:
-      return DW_FORM_addr;
-    case dw_val_class_section_offset:
-      return DW_FORM_data;
-    case dw_val_class_str:
-      return DW_FORM_string;
-    default:
-      abort ();
+      line_info = &line_info_table[i];
+      fprintf (outfile, "%5d: ", i);
+      fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]);
+      fprintf (outfile, "%6d", line_info->dw_line_num);
+      fprintf (outfile, "\n");
     }
+
+  fprintf (outfile, "\n\n");
 }
 
-/* Output the encoding of an attribute value.  */
+/* Print the information collected for a given DIE.  */
+
+void
+debug_dwarf_die (die)
+     dw_die_ref die;
+{
+  print_die (die, stderr);
+}
+
+/* Print all DWARF information collected for the compilation unit.
+   This routine is a debugging aid only.  */
+
+void
+debug_dwarf ()
+{
+  print_indent = 0;
+  print_die (comp_unit_die, stderr);
+  print_dwarf_line_table (stderr);
+}
+\f
+/* 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
-output_value_format (v)
-     dw_val_ref v;
+add_sibling_attributes(die)
+     register dw_die_ref die;
 {
-  enum dwarf_form form = value_format (v);
+  register dw_die_ref c;
+  register dw_attr_ref attr;
+  if (die != comp_unit_die && die->die_child != NULL)
+    {
+      attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+      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;
 
-  output_uleb128 (form);
-  if (flag_verbose_asm)
-    fprintf (asm_out_file, " (%s)", dwarf_form_name (form));
+      /* 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;
 
-  fputc ('\n', asm_out_file);
+      die->die_attr = attr;
+    }
+
+  for (c = die->die_child; c != NULL; c = c->die_sib)
+    add_sibling_attributes (c);
 }
 
-/* Output the .debug_abbrev section which defines the DIE abbreviation
-   table.  */
+/* The format of each DIE (and its attribute value pairs)
+   is encoded in an abbreviation table.  This routine builds the
+   abbreviation table and assigns a unique abbreviation id for
+   each abbreviation entry.  The children of each die are visited
+   recursively.  */
 
 static void
-output_abbrev_section ()
+build_abbrev_table (die)
+     register dw_die_ref die;
 {
-  unsigned long abbrev_id;
-
-  dw_attr_ref a_attr;
+  register unsigned long abbrev_id;
+  register unsigned long n_alloc;
+  register dw_die_ref c;
+  register dw_attr_ref d_attr, 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, " (abbrev code)");
-
-      fputc ('\n', asm_out_file);
-      output_uleb128 (abbrev->die_tag);
-      if (flag_verbose_asm)
-       fprintf (asm_out_file, " (TAG: %s)",
-                dwarf_tag_name (abbrev->die_tag));
+      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;
 
-      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);
+             while (a_attr != NULL && d_attr != NULL)
+               {
+                 if ((a_attr->dw_attr != d_attr->dw_attr)
+                     || (value_format (&a_attr->dw_attr_val)
+                         != value_format (&d_attr->dw_attr_val)))
+                   break;
 
-      if (flag_verbose_asm)
-       fprintf (asm_out_file, "\t%s %s",
-                ASM_COMMENT_START,
-                (abbrev->die_child != NULL
-                 ? "DW_children_yes" : "DW_children_no"));
+                 a_attr = a_attr->dw_attr_next;
+                 d_attr = d_attr->dw_attr_next;
+               }
 
-      fputc ('\n', asm_out_file);
+             if (a_attr == NULL && d_attr == NULL)
+               break;
+           }
+       }
+    }
 
-      for (a_attr = abbrev->die_attr; a_attr != NULL;
-          a_attr = a_attr->dw_attr_next)
+  if (abbrev_id >= abbrev_die_table_in_use)
+    {
+      if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
        {
-         output_uleb128 (a_attr->dw_attr);
-         if (flag_verbose_asm)
-           fprintf (asm_out_file, " (%s)",
-                    dwarf_attr_name (a_attr->dw_attr));
+         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);
 
-         fputc ('\n', asm_out_file);
-         output_value_format (&a_attr->dw_attr_val);
+         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;
        }
 
-      fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP);
+      ++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);
 }
+\f
+/* Return the size of a string, including the null byte.  */
 
-/* Output location description stack opcode's operands (if any).  */
+static unsigned long
+size_of_string (str)
+     register char *str;
+{
+  register unsigned long size = 0;
+  register unsigned long slen = strlen (str);
+  register unsigned long i;
+  register unsigned c;
 
-static void
-output_loc_operands (loc)
+  for (i = 0; i < slen; ++i)
+    {
+      c = str[i];
+      if (c == '\\')
+       ++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 dw_val_ref val1 = &loc->dw_loc_oprnd1;
-  register dw_val_ref val2 = &loc->dw_loc_oprnd2;
+  register unsigned long size = 1;
 
   switch (loc->dw_loc_opc)
     {
     case DW_OP_addr:
-      ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr);
-      fputc ('\n', asm_out_file);
+      size += PTR_SIZE;
       break;
     case DW_OP_const1u:
     case DW_OP_const1s:
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
-      fputc ('\n', asm_out_file);
+      size += 1;
       break;
     case DW_OP_const2u:
     case DW_OP_const2s:
-      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      size += 2;
       break;
     case DW_OP_const4u:
     case DW_OP_const4s:
-      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      size += 4;
       break;
     case DW_OP_const8u:
     case DW_OP_const8s:
-      abort ();
-      fputc ('\n', asm_out_file);
+      size += 8;
       break;
     case DW_OP_constu:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
       break;
     case DW_OP_consts:
-      output_sleb128 (val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
       break;
     case DW_OP_pick:
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      size += 1;
       break;
     case DW_OP_plus_uconst:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
       break;
     case DW_OP_skip:
     case DW_OP_bra:
-      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      size += 2;
       break;
     case DW_OP_breg0:
     case DW_OP_breg1:
@@ -3714,1022 +4047,848 @@ output_loc_operands (loc)
     case DW_OP_breg29:
     case DW_OP_breg30:
     case DW_OP_breg31:
-      output_sleb128 (val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
       break;
     case DW_OP_regx:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
       break;
     case DW_OP_fbreg:
-      output_sleb128 (val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
       break;
     case DW_OP_bregx:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
-      output_sleb128 (val2->v.val_int);
-      fputc ('\n', asm_out_file);
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+      size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
       break;
     case DW_OP_piece:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
       break;
     case DW_OP_deref_size:
     case DW_OP_xderef_size:
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
-      fputc ('\n', asm_out_file);
+      size += 1;
       break;
     default:
       break;
     }
+
+  return size;
 }
 
-/* Compute the offset of a sibling.  */
+/* Return the size of a series of location descriptors.  */
 
 static unsigned long
-sibling_offset (die)
-     dw_die_ref die;
+size_of_locs (loc)
+     register dw_loc_descr_ref loc;
 {
-  unsigned long offset;
+  register unsigned long size = 0;
 
-  if (die->die_child_last == NULL)
-    offset = die->die_offset + size_of_die (die);
+  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
-    offset = sibling_offset (die->die_child_last) + 1;
+    log = floor_log2 (value);
 
-  return offset;
+  log = log / 8;
+  log = 1 << (floor_log2 (log) + 1);
+
+  return log;
 }
 
-/* Output the DIE and its attributes.  Called recursively to generate
-   the definitions of each child DIE.  */
+/* Return the size of a DIE, as it is represented in the
+   .debug_info section.  */
 
-static void
-output_die (die)
+static unsigned long
+size_of_die (die)
      register dw_die_ref die;
 {
+  register unsigned long size = 0;
   register dw_attr_ref a;
-  register dw_die_ref c;
-  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, " (DIE (0x%x) %s)",
-            die->die_offset, dwarf_tag_name (die->die_tag));
-
-  fputc ('\n', asm_out_file);
 
+  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:
-         ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file,
-                                      a->dw_attr_val.v.val_addr);
+         size += PTR_SIZE;
          break;
-
        case dw_val_class_loc:
-         size = size_of_locs (a->dw_attr_val.v.val_loc);
-
-         /* Output the block length for this list of location operations.  */
-         switch (constant_size (size))
-           {
-           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)
-           {
-             /* 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));
-
-             fputc ('\n', asm_out_file);
+         {
+           register unsigned long lsize
+             = size_of_locs (a->dw_attr_val.v.val_loc);
 
-             /* Output the operand(s) (if any).  */
-             output_loc_operands (loc);
-           }
+           /* Block length.  */
+           size += constant_size (lsize);
+           size += lsize;
+         }
          break;
-
        case dw_val_class_const:
-         ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int);
+         size += 4;
          break;
-
        case dw_val_class_unsigned_const:
-         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 ();
-           }
+         size += constant_size (a->dw_attr_val.v.val_unsigned);
          break;
-
        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_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);
+         size += 1 + 8; /* block */
          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);
-           }
+         size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */
          break;
-
        case dw_val_class_flag:
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag);
+         size += 1;
          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;
-         else if (a->dw_attr == DW_AT_sibling)
-           ref_offset = sibling_offset(die);
-         else
-           abort ();
-
-         ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset);
+         size += DWARF_OFFSET_SIZE;
          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_OFFSET_ASM_OP,
-                  stripattributes (FRAME_SECTION), ref_offset);
+         size += DWARF_OFFSET_SIZE;
          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_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
-         && 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));
-
-         fputc ('\n', asm_out_file);
-       }
-    }
-
-  for (c = die->die_child; c != NULL; c = c->die_sib)
-    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);
+         size += PTR_SIZE;
+         break;
+       case dw_val_class_section_offset:
+         size += DWARF_OFFSET_SIZE;
+         break;
+       case dw_val_class_str:
+         size += size_of_string (a->dw_attr_val.v.val_str);
+         break;
+       default:
+         abort ();
+       }
     }
+
+  return size;
 }
 
-/* Output the compilation unit that appears at the beginning of the
-   .debug_info section, and precedes the DIE descriptions.  */
+/* Size the debgging information associted with a given DIE.
+   Visits the DIE's children recursively.  Updates the global
+   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
-output_compilation_unit_header ()
+calc_die_sizes (die)
+     dw_die_ref die;
 {
-  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);
-
-  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 number", ASM_COMMENT_START);
-
-  fputc ('\n', asm_out_file);
-  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);
+  register dw_die_ref c;
+  die->die_offset = next_die_offset;
+  next_die_offset += size_of_die (die);
 
-  fputc ('\n', asm_out_file);
-  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);
+  for (c = die->die_child; c != NULL; c = c->die_sib)
+    calc_die_sizes (c);
 
-  fputc ('\n', asm_out_file);
+  if (die->die_child != NULL)
+    /* Count the null byte used to terminate sibling lists.  */
+    next_die_offset += 1;
 }
 
-/* Generate a new label for the CFI info to refer to.  */
+/* Return the size of the line information prolog generated for the
+   compilation unit.  */
 
-static char *
-dwarf2out_cfi_label ()
+static unsigned long
+size_of_line_prolog ()
 {
-  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;
-}
+  register unsigned long size;
+  register unsigned long ft_index;
 
-/* Add CFI to the current fde at the PC value indicated by LABEL if specified,
-   or to the CIE if LABEL is NULL.  */
+  size = DWARF_LINE_PROLOG_HEADER_SIZE;
 
-static void
-add_fde_cfi (label, cfi)
-     register char *label;
-     register dw_cfi_ref cfi;
-{
-  if (label)
-    {
-      register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+  /* Count the size of the table giving number of args for each
+     standard opcode.  */
+  size += DWARF_LINE_OPCODE_BASE - 1;
 
-      if (*label == 0)
-       label = dwarf2out_cfi_label ();
+  /* Include directory table is empty (at present).  Count only the
+     the null byte used to terminate the table.  */
+  size += 1;
 
-      if (fde->dw_fde_current_label == NULL
-         || strcmp (label, fde->dw_fde_current_label) != 0)
-       {
-         register dw_cfi_ref xcfi;
+  for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
+    {
+      /* File name entry.  */
+      size += size_of_string (file_table[ft_index]);
 
-         fde->dw_fde_current_label = label = xstrdup (label);
+      /* Include directory index.  */
+      size += size_of_uleb128 (0);
 
-         /* 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);
-       }
+      /* Modification time.  */
+      size += size_of_uleb128 (0);
 
-      add_cfi (&fde->dw_fde_cfi, cfi);
+      /* File length in bytes.  */
+      size += size_of_uleb128 (0);
     }
 
-  else
-    add_cfi (&cie_cfi_head, cfi);
+  /* Count the file table terminator.  */
+  size += 1;
+  return size;
 }
 
-/* Subroutine of lookup_cfa.  */
+/* Return the size of the line information generated for this
+   compilation unit.  */
 
-static inline void
-lookup_cfa_1 (cfi, regp, offsetp)
-     register dw_cfi_ref cfi;
-     register unsigned long *regp;
-     register long *offsetp;
+static unsigned long
+size_of_line_info ()
 {
-  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;
-    }
-}
+  register unsigned long size;
+  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;
 
-/* Find the previous value for the CFA.  */
+  /* Version number.  */
+  size = 2;
 
-static void
-lookup_cfa (regp, offsetp)
-     register unsigned long *regp;
-     register long *offsetp;
-{
-  register dw_cfi_ref cfi;
+  /* Prolog length specifier.  */
+  size += DWARF_OFFSET_SIZE;
 
-  *regp = (unsigned long) -1;
-  *offsetp = 0;
+  /* Prolog.  */
+  size += size_of_line_prolog ();
 
-  for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
-    lookup_cfa_1 (cfi, regp, offsetp);
+  /* Set address register instruction.  */
+  size += 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE;
 
-  if (fde_table_in_use)
+  current_file = 1;
+  current_line = 1;
+  for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
     {
-      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);
+      register dw_line_info_ref line_info;
+
+      /* Advance pc instruction.  */
+      size += 1 + 2;
+      line_info = &line_info_table[lt_index];
+      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;
+           }
+       }
     }
-}
 
-/* 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.  */
+  /* Advance pc instruction.  */
+  size += 1 + 2;
 
-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;
+  /* End of line number info. marker.  */
+  size += 1 + size_of_uleb128 (1) + 1;
 
-  reg = DWARF_FRAME_REGNUM (reg);
-  lookup_cfa (&old_reg, &old_offset);
+  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);
 
-  if (reg == old_reg && offset == old_offset)
-    return;
+             /* Generate line entry instruction.  */
+             size += 1;
+           }
+       }
 
-  cfi = new_cfi ();
+      ++lt_index;
 
-  if (reg == old_reg)
-    {
-      cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
-      cfi->dw_cfi_oprnd1.dw_cfi_offset = offset;
-    }
+      /* 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;
 
-#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
+         /* Advance pc instruction.  */
+         size += 1 + 2;
 
-  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;
+         /* End of line number info. marker.  */
+         size += 1 + size_of_uleb128 (1) + 1;
+       }
     }
 
-  add_fde_cfi (label, cfi);
+  return size;
 }
 
-/* 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.  */
+/* Return the size of the .debug_pubnames table  generated for the
+   compilation unit.  */
 
-static void
-reg_save (label, reg, sreg, offset)
-     register char * label;
-     register unsigned reg;
-     register unsigned sreg;
-     register long offset;
+static unsigned long
+size_of_pubnames ()
 {
-  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;
+  register unsigned long size;
+  register unsigned i;
 
-      offset /= DWARF_CIE_DATA_ALIGNMENT;
-      assert (offset >= 0);
-      cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
-    }
-  else
+  size = DWARF_PUBNAMES_HEADER_SIZE;
+  for (i = 0; i < pubname_table_in_use; ++i)
     {
-      cfi->dw_cfi_opc = DW_CFA_register;
-      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
+      register pubname_ref p = &pubname_table[i];
+      size += DWARF_OFFSET_SIZE + size_of_string (p->name);
     }
 
-  add_fde_cfi (label, cfi);
+  size += DWARF_OFFSET_SIZE;
+  return size;
 }
 
-/* Entry point for saving a register.  REG is the GCC register number.
-   LABEL and OFFSET are passed to reg_save.  */
+/* Return the size of the information in the .debug_aranges seciton.  */
 
-void
-dwarf2out_reg_save (label, reg, offset)
-     register char * label;
-     register unsigned reg;
-     register long offset;
+static unsigned long
+size_of_aranges ()
 {
-  reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset);
-}
+  register unsigned long size;
 
-/* Record the initial position of the return address.  RTL is
-   INCOMING_RETURN_ADDR_RTX.  */
+  size = DWARF_ARANGES_HEADER_SIZE;
 
-static void
-initial_return_save (rtl)
-     register rtx rtl;
-{
-  unsigned reg = -1;
-  long offset = 0;
+  /* Count the address/length pair for this compilation unit.  */
+  size += 2 * PTR_SIZE;
+  size += 2 * PTR_SIZE * arange_table_in_use;
 
-  switch (GET_CODE (rtl))
+  /* Count the two zero words used to terminated the address range table.  */
+  size += 2 * PTR_SIZE;
+  return size;
+}
+\f
+/* Select the encoding of an attribute value.  */
+
+static enum dwarf_form
+value_format (v)
+     dw_val_ref v;
+{
+  switch (v->val_class)
     {
-    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 dw_val_class_addr:
+      return DW_FORM_addr;
+    case dw_val_class_loc:
+      switch (constant_size (size_of_locs (v->v.val_loc)))
        {
-       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;
+       case 1:
+         return DW_FORM_block1;
+       case 2:
+         return DW_FORM_block2;
        default:
          abort ();
        }
-      break;
+    case dw_val_class_const:
+      return DW_FORM_data4;
+    case dw_val_class_unsigned_const:
+      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:
+      return DW_FORM_flag;
+    case dw_val_class_die_ref:
+      return DW_FORM_ref;
+    case dw_val_class_fde_ref:
+      return DW_FORM_data;
+    case dw_val_class_lbl_id:
+      return DW_FORM_addr;
+    case dw_val_class_section_offset:
+      return DW_FORM_data;
+    case dw_val_class_str:
+      return DW_FORM_string;
     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.  */
+/* Output the encoding of an attribute value.  */
 
-void
-dwarf2out_frame_debug (insn)
-     rtx insn;
+static void
+output_value_format (v)
+     dw_val_ref v;
 {
-  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 ();
-               }
+  enum dwarf_form form = value_format (v);
 
-             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;
+  output_uleb128 (form);
+  if (flag_verbose_asm)
+    fprintf (asm_out_file, " (%s)", dwarf_form_name (form));
 
-       case CONST_INT:
-         cfa_temp_reg = REGNO (dest);
-         cfa_temp_value = INTVAL (src);
-         break;
+  fputc ('\n', asm_out_file);
+}
 
-       default:
-         abort ();
-       }
-      dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
-      break;
+/* Output the .debug_abbrev section which defines the DIE abbreviation
+   table.  */
 
-    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;
+static void
+output_abbrev_section ()
+{
+  unsigned long abbrev_id;
 
-         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;
+  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];
 
-         offset = -cfa_store_offset;
-         break;
+      output_uleb128 (abbrev_id);
+      if (flag_verbose_asm)
+       fprintf (asm_out_file, " (abbrev code)");
 
-         /* With an offset.  */
-       case PLUS:
-       case MINUS:
-         offset = INTVAL (XEXP (XEXP (dest, 0), 1));
-         if (GET_CODE (src) == MINUS)
-           offset = -offset;
+      fputc ('\n', asm_out_file);
+      output_uleb128 (abbrev->die_tag);
+      if (flag_verbose_asm)
+       fprintf (asm_out_file, " (TAG: %s)",
+                dwarf_tag_name (abbrev->die_tag));
 
-         assert (cfa_store_reg == REGNO (XEXP (XEXP (dest, 0), 0)));
-         offset -= cfa_store_offset;
-         break;
+      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);
 
-       default:
-         abort ();
+      if (flag_verbose_asm)
+       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, " (%s)",
+                    dwarf_attr_name (a_attr->dw_attr));
+
+         fputc ('\n', asm_out_file);
+         output_value_format (&a_attr->dw_attr_val);
        }
-      dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
-      dwarf2out_reg_save (label, REGNO (src), offset);
-      break;
 
-    default:
-      abort ();
+      fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP);
     }
 }
 
-/* Return the size of a Call Frame Instruction.  */
+/* Output location description stack opcode's operands (if any).  */
 
-static unsigned long
-size_of_cfi (cfi)
-     dw_cfi_ref cfi;
+static void
+output_loc_operands (loc)
+     register dw_loc_descr_ref loc;
 {
-  register unsigned long size;
+  register dw_val_ref val1 = &loc->dw_loc_oprnd1;
+  register dw_val_ref val2 = &loc->dw_loc_oprnd2;
 
-  /* Count the 1-byte opcode */
-  size = 1;
-  switch (cfi->dw_cfi_opc)
+  switch (loc->dw_loc_opc)
     {
-    case DW_CFA_offset:
-      size += size_of_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
+    case DW_OP_addr:
+      ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr);
+      fputc ('\n', asm_out_file);
       break;
-    case DW_CFA_set_loc:
-      size += PTR_SIZE;
+    case DW_OP_const1u:
+    case DW_OP_const1s:
+      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
+      fputc ('\n', asm_out_file);
       break;
-    case DW_CFA_advance_loc1:
-      size += 1;
+    case DW_OP_const2u:
+    case DW_OP_const2s:
+      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
+      fputc ('\n', asm_out_file);
       break;
-    case DW_CFA_advance_loc2:
-      size += 2;
+    case DW_OP_const4u:
+    case DW_OP_const4s:
+      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int);
+      fputc ('\n', asm_out_file);
       break;
-    case DW_CFA_advance_loc4:
-      size += 4;
+    case DW_OP_const8u:
+    case DW_OP_const8s:
+      abort ();
+      fputc ('\n', asm_out_file);
       break;
-#ifdef MIPS_DEBUGGING_INFO
-    case DW_CFA_MIPS_advance_loc8:
-      size += 8;
+    case DW_OP_constu:
+      output_uleb128 (val1->v.val_unsigned);
+      fputc ('\n', asm_out_file);
       break;
-#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);
+    case DW_OP_consts:
+      output_sleb128 (val1->v.val_int);
+      fputc ('\n', asm_out_file);
       break;
-    case DW_CFA_restore_extended:
-    case DW_CFA_undefined:
-      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+    case DW_OP_pick:
+      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int);
+      fputc ('\n', asm_out_file);
       break;
-    case DW_CFA_same_value:
-    case DW_CFA_def_cfa_register:
-      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+    case DW_OP_plus_uconst:
+      output_uleb128 (val1->v.val_unsigned);
+      fputc ('\n', asm_out_file);
       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);
+    case DW_OP_skip:
+    case DW_OP_bra:
+      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
+      fputc ('\n', asm_out_file);
       break;
-    case DW_CFA_def_cfa_offset:
-      size += size_of_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+    case DW_OP_breg0:
+    case DW_OP_breg1:
+    case DW_OP_breg2:
+    case DW_OP_breg3:
+    case DW_OP_breg4:
+    case DW_OP_breg5:
+    case DW_OP_breg6:
+    case DW_OP_breg7:
+    case DW_OP_breg8:
+    case DW_OP_breg9:
+    case DW_OP_breg10:
+    case DW_OP_breg11:
+    case DW_OP_breg12:
+    case DW_OP_breg13:
+    case DW_OP_breg14:
+    case DW_OP_breg15:
+    case DW_OP_breg16:
+    case DW_OP_breg17:
+    case DW_OP_breg18:
+    case DW_OP_breg19:
+    case DW_OP_breg20:
+    case DW_OP_breg21:
+    case DW_OP_breg22:
+    case DW_OP_breg23:
+    case DW_OP_breg24:
+    case DW_OP_breg25:
+    case DW_OP_breg26:
+    case DW_OP_breg27:
+    case DW_OP_breg28:
+    case DW_OP_breg29:
+    case DW_OP_breg30:
+    case DW_OP_breg31:
+      output_sleb128 (val1->v.val_int);
+      fputc ('\n', asm_out_file);
+      break;
+    case DW_OP_regx:
+      output_uleb128 (val1->v.val_unsigned);
+      fputc ('\n', asm_out_file);
+      break;
+    case DW_OP_fbreg:
+      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_int);
+      fputc ('\n', asm_out_file);
+      break;
+    case DW_OP_piece:
+      output_uleb128 (val1->v.val_unsigned);
+      fputc ('\n', asm_out_file);
+      break;
+    case DW_OP_deref_size:
+    case DW_OP_xderef_size:
+      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
+      fputc ('\n', asm_out_file);
       break;
     default:
       break;
     }
-
-    return size;
 }
 
-/* Return the size of an FDE sans the length word.  */
+/* Compute the offset of a sibling.  */
 
-static inline unsigned long
-size_of_fde (fde, npad)
-    dw_fde_ref fde;
-    unsigned long *npad;
+static unsigned long
+sibling_offset (die)
+     dw_die_ref die;
 {
-  register dw_cfi_ref cfi;
-  register unsigned long aligned_size;
-  register unsigned long size;
+  unsigned long offset;
 
-  size = DWARF_FDE_HEADER_SIZE;
-  for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-    size += size_of_cfi(cfi);
+  if (die->die_child_last == NULL)
+    offset = die->die_offset + size_of_die (die);
+  else
+    offset = sibling_offset (die->die_child_last) + 1;
 
-  /* Round the size up to a word boundary.  */
-  aligned_size = DWARF_ROUND (size, PTR_SIZE);
-  *npad = aligned_size - size;
-  return aligned_size;
+  return offset;
 }
 
-/* Calculate the size of the FDE table, and establish the offset
-   of each FDE in the .debug_frame section.  */
+/* Output the DIE and its attributes.  Called recursively to generate
+   the definitions of each child DIE.  */
 
 static void
-calc_fde_sizes ()
+output_die (die)
+     register dw_die_ref die;
 {
-  register unsigned long i;
-  register dw_fde_ref fde;
-  register unsigned long fde_size;
-  register dw_cfi_ref cfi;
-  unsigned long fde_pad;
+  register dw_attr_ref a;
+  register dw_die_ref c;
+  register unsigned long ref_offset;
+  register unsigned long size;
+  register dw_loc_descr_ref loc;
+  register int i;
 
-  cie_size = DWARF_CIE_HEADER_SIZE;
-  for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
-    cie_size += size_of_cfi (cfi);
+  output_uleb128 (die->die_abbrev);
+  if (flag_verbose_asm)
+    fprintf (asm_out_file, " (DIE (0x%x) %s)",
+            die->die_offset, dwarf_tag_name (die->die_tag));
 
-  /* Initialize the beginning FDE offset.  */
-  next_fde_offset = DWARF_ROUND (cie_size, PTR_SIZE);
+  fputc ('\n', asm_out_file);
 
-  for (i = 0; i < fde_table_in_use; ++i)
+  for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
     {
-      fde = &fde_table[i];
-      fde->dw_fde_offset = next_fde_offset;
-      fde_size = size_of_fde (fde, &fde_pad);
-      next_fde_offset += fde_size;
-    }
-}
+      switch (a->dw_attr_val.val_class)
+       {
+       case dw_val_class_addr:
+         ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file,
+                                      a->dw_attr_val.v.val_addr);
+         break;
 
-/* Output a Call Frame Information opcode and its operand(s).  */
+       case dw_val_class_loc:
+         size = size_of_locs (a->dw_attr_val.v.val_loc);
 
-static void
-output_cfi (cfi, fde)
-     register dw_cfi_ref cfi;
-     register dw_fde_ref fde;
-{
-  if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
-    {
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
-                             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 0x%x",
-                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
-      fputc ('\n', asm_out_file);
-    }
+         /* Output the block length for this list of location operations.  */
+         switch (constant_size (size))
+           {
+           case 1:
+             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size);
+             break;
+           case 2:
+             ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size);
+             break;
+           default:
+             abort ();
+           }
 
-  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, column 0x%x",
-                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+         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);
-      output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-      fputc ('\n', asm_out_file);
-    }
-  else if (cfi->dw_cfi_opc == DW_CFA_restore)
-    {
-      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_restore, column 0x%x",
-                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+         fputc ('\n', asm_out_file);
+         for (loc = a->dw_attr_val.v.val_loc; loc != NULL;
+              loc = loc->dw_loc_next)
+           {
+             /* 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));
 
-      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));
+             fputc ('\n', asm_out_file);
 
-      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);
-          fputc ('\n', asm_out_file);
-         break;
-       case DW_CFA_advance_loc1:
-         /* TODO: not currently implemented.  */
-         abort ();
-         break;
-       case DW_CFA_advance_loc2:
-          ASM_OUTPUT_DWARF_DELTA2 (asm_out_file,
-                                  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_current_label);
-          fputc ('\n', asm_out_file);
-         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+             /* Output the operand(s) (if any).  */
+             output_loc_operands (loc);
+           }
          break;
-#ifdef MIPS_DEBUGGING_INFO
-       case DW_CFA_MIPS_advance_loc8:
-         /* TODO: not currently implemented.  */
-         abort ();
+
+       case dw_val_class_const:
+         ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int);
          break;
-#endif
-       case DW_CFA_offset_extended:
-       case DW_CFA_def_cfa:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-          fputc ('\n', asm_out_file);
-         output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-          fputc ('\n', asm_out_file);
+
+       case dw_val_class_unsigned_const:
+         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;
+           case 8:
+             ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
+                                     a->dw_attr_val.v.val_long_long.hi,
+                                     a->dw_attr_val.v.val_long_long.low);
+             break;
+           default:
+             abort ();
+           }
          break;
-       case DW_CFA_restore_extended:
-       case DW_CFA_undefined:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-          fputc ('\n', asm_out_file);
+
+       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_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_CFA_same_value:
-       case DW_CFA_def_cfa_register:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-          fputc ('\n', asm_out_file);
+
+       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_CFA_register:
-         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);
-          fputc ('\n', asm_out_file);
+
+       case dw_val_class_flag:
+         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag);
          break;
-       case DW_CFA_def_cfa_offset:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
-          fputc ('\n', asm_out_file);
+
+       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;
+         else if (a->dw_attr == DW_AT_sibling)
+           ref_offset = sibling_offset(die);
+         else
+           abort ();
+
+         ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset);
          break;
-       default:
+
+       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_OFFSET_ASM_OP,
+                  stripattributes (FRAME_SECTION), ref_offset);
          break;
-       }
-     }
-}
 
-/* 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.  */
+       case dw_val_class_lbl_id:
+         ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id);
+         break;
 
-static void
-output_call_frame_info ()
-{
-  register unsigned long i, j;
-  register dw_fde_ref fde;
-  register unsigned long fde_size;
-  register dw_cfi_ref cfi;
-  unsigned long fde_pad;
+       case dw_val_class_section_offset:
+         ASM_OUTPUT_DWARF_OFFSET (asm_out_file,
+                                  stripattributes
+                                  (a->dw_attr_val.v.val_section));
+         break;
 
-  /* 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;
+       case dw_val_class_str:
+         ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str);
+         break;
 
-  /* (re-)initialize the beginning FDE offset.  */
-  next_fde_offset = DWARF_ROUND (cie_size, PTR_SIZE);
+       default:
+         abort ();
+       }
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
+      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));
 
-  /* Output the CIE. */
-  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);
+         fputc ('\n', asm_out_file);
+       }
+    }
 
-  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);
+  for (c = die->die_child; c != NULL; c = c->die_sib)
+    output_die (c);
 
-  fputc ('\n', asm_out_file);
-  if (DWARF_OFFSET_SIZE == 8)
+  if (die->die_child != NULL)
     {
-      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
+      /* 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);
     }
+}
 
-  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);
+/* Output the compilation unit that appears at the beginning of the
+   .debug_info section, and precedes the DIE descriptions.  */
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+static void
+output_compilation_unit_header ()
+{
+  ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE);
   if (flag_verbose_asm)
-    fprintf (asm_out_file, "\t%s CIE Augmentation (none)", ASM_COMMENT_START);
+    fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.",
+            ASM_COMMENT_START);
 
   fputc ('\n', asm_out_file);
-  output_uleb128 (1);
+  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
   if (flag_verbose_asm)
-    fprintf (asm_out_file, " (CIE Code Alignment Factor)");
+    fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START);
 
   fputc ('\n', asm_out_file);
-  output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
+  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (ABBREV_SECTION));
   if (flag_verbose_asm)
-    fprintf (asm_out_file, " (CIE Data Alignment Factor)");
+    fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section",
+            ASM_COMMENT_START);
 
   fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
+  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
   if (flag_verbose_asm)
-    fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
+    fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START);
 
   fputc ('\n', asm_out_file);
-
-  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 = 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);
-
-      fputc ('\n', asm_out_file);
-    }
-
-  /* Loop through all of the FDE's.  */
-  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_DATA (asm_out_file, fde_size - DWARF_OFFSET_SIZE);
-      if (flag_verbose_asm)
-       fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
-
-      fputc ('\n', asm_out_file);
-      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);
-
-      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);
-
-      fputc ('\n', asm_out_file);
-      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);
-
-      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);
-
-      /* 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);
-
-         fputc ('\n', asm_out_file);
-       }
-    }
 }
 
 /* The DWARF2 pubname for a nested thingy looks like "A::f".  The output
@@ -5573,25 +5732,6 @@ type_is_enum (type)
   return TREE_CODE (type) == ENUMERAL_TYPE;
 }
 
-/* Return the register number described by a given RTL node.  */
-
-static unsigned
-reg_number (rtl)
-     register rtx rtl;
-{
-  register unsigned regno = REGNO (rtl);
-
-  if (regno >= FIRST_PSEUDO_REGISTER)
-    {
-      warning_with_decl (dwarf_last_decl, "internal regno botch: regno = %d\n",
-                        regno);
-      regno = 0;
-    }
-
-  regno = DBX_REGISTER_NUMBER (regno);
-  return regno;
-}
-
 /* Return a location descriptor that designates a machine register.  */
 
 static dw_loc_descr_ref
@@ -6371,6 +6511,9 @@ add_bound_info (subrange_die, bound_attr, bound)
 
       /* Else leave out the attribute.  */
       break;
+
+    default:
+      abort ();
     }
 }
 
@@ -8534,7 +8677,7 @@ dwarf2out_decl (decl)
       /* 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;
+       context_die = NULL;
 
       break;
 
@@ -8544,9 +8687,6 @@ dwarf2out_decl (decl)
 
   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
@@ -8589,58 +8729,6 @@ dwarf2out_label (insn)
     }
 }
 
-/* Output a marker (i.e. a label) for the beginning of a function, before
-   the prologue.  */
-
-void
-dwarf2out_begin_prologue ()
-{
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  register dw_fde_ref fde;
-
-  function_section (current_function_decl);
-  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));
-    }
-
-  /* Record the FDE associated with this function.  */
-  current_funcdef_fde = fde_table_in_use;
-
-  /* Add the new FDE at the end of the fde_table.  */
-  fde = &fde_table[fde_table_in_use++];
-  fde->dw_fde_begin = xstrdup (label);
-  fde->dw_fde_current_label = NULL;
-  fde->dw_fde_end = NULL;
-  fde->dw_fde_cfi = NULL;
-}
-
-/* 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
-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.        */
-  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
    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.
@@ -8855,13 +8943,6 @@ dwarf2out_init (asm_out_file, main_input_filename)
   /* 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 ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
-  fde_table_allocated = FDE_TABLE_INCREMENT;
-  fde_table_in_use = 0;
-
   /* 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 
@@ -8871,14 +8952,9 @@ dwarf2out_init (asm_out_file, main_input_filename)
 
   ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
 
-  /* 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
+  /* Initialize the frame unwind information.  Eventually this should be
+     called from compile_file instead.  */
+  dwarf2out_frame_init ();
 }
 
 /* Output stuff that dwarf requires at the end of every file,
@@ -8908,6 +8984,10 @@ dwarf2out_finish ()
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
 #endif
 
+  /* Output the frame unwind information.  Eventually this should be called
+     from compile_file instead.  */
+  dwarf2out_frame_finish ();
+
   /* Output the source line correspondence table.  */
   if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
     {
@@ -8936,9 +9016,6 @@ dwarf2out_finish ()
   next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
   calc_die_sizes (comp_unit_die);
 
-  /* calculate sizes/offsets for FDEs.  */
-  calc_fde_sizes ();
-
   /* Output debugging information.  */
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_SECTION (asm_out_file, DEBUG_SECTION);
@@ -8955,9 +9032,6 @@ dwarf2out_finish ()
 
   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);