OSDN Git Service

Changes to distinguish typedef from original type in debug output.
[pf3gnuchains/gcc-fork.git] / gcc / dbxout.c
index 44e55b2..cb06b16 100644 (file)
@@ -1,5 +1,5 @@
 /* Output dbx-format symbol table information from GNU compiler.
-   Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* Output dbx-format symbol table data.
@@ -77,13 +78,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "regs.h"
 #include "insn-config.h"
 #include "reload.h"
+#include "defaults.h"
+#include "output.h" /* ASM_OUTPUT_SOURCE_LINE may refer to sdb functions.  */
 
 #ifndef errno
 extern int errno;
 #endif
 
 #ifdef XCOFF_DEBUGGING_INFO
-#include "xcoff.h"
+#include "xcoffout.h"
 #endif
 
 #ifndef ASM_STABS_OP
@@ -94,8 +97,8 @@ extern int errno;
 #define ASM_STABN_OP ".stabn"
 #endif
 
-#ifndef DBX_DECL_STABS_CODE
-#define DBX_DECL_STABS_CODE N_LSYM
+#ifndef DBX_TYPE_DECL_STABS_CODE
+#define DBX_TYPE_DECL_STABS_CODE N_LSYM
 #endif
 
 #ifndef DBX_STATIC_CONST_VAR_CODE
@@ -110,10 +113,34 @@ extern int errno;
 #define DBX_REGPARM_STABS_LETTER 'P'
 #endif
 
+/* This is used for parameters passed by invisible reference in a register.  */
+#ifndef GDB_INV_REF_REGPARM_STABS_LETTER
+#define GDB_INV_REF_REGPARM_STABS_LETTER 'a'
+#endif
+
+#ifndef DBX_MEMPARM_STABS_LETTER
+#define DBX_MEMPARM_STABS_LETTER 'p'
+#endif
+
+#ifndef FILE_NAME_JOINER
+#define FILE_NAME_JOINER "/"
+#endif
+
 /* Nonzero means if the type has methods, only output debugging
-   information if methods are actually written to the asm file.  */
+   information if methods are actually written to the asm file.  This
+   optimization only works if the debugger can detect the special C++
+   marker.  */
+
+#define MINIMAL_DEBUG 1
 
-static int flag_minimal_debug = 1;
+#ifdef NO_DOLLAR_IN_LABEL
+#ifdef NO_DOT_IN_LABEL
+#undef MINIMAL_DEBUG
+#define MINIMAL_DEBUG 0
+#endif
+#endif
+
+static int flag_minimal_debug = MINIMAL_DEBUG;
 
 /* Nonzero if we have actually used any of the GDB extensions
    to the debugging format.  The idea is that we use them for the
@@ -122,6 +149,11 @@ static int flag_minimal_debug = 1;
 
 static int have_used_extensions = 0;
 
+/* Number for the next N_SOL filename stabs label.  The number 0 is reserved
+   for the N_SO filename stabs label.  */
+
+static int source_label_number = 1;
+
 char *getpwd ();
 
 /* Typical USG systems don't have stab.h, and they also have
@@ -135,7 +167,7 @@ char *getpwd ();
 #define FORCE_TEXT
 #endif
 
-#if defined (USG) || defined (MIPS)
+#if defined (USG) || defined (NO_STAB_H) || defined (CROSS_COMPILE)
 #include "gstab.h"  /* If doing DBX on sysV, use our own stab.h.  */
 #else
 #include <stab.h>  /* On BSD, use the system's stab.h.  */
@@ -184,15 +216,28 @@ static char *cwd;
 
 enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED};
 
-/* Vector recording the status of describing C data types.
+/* Structure recording information about a C data type.
+   The status element says whether we have yet output
+   the definition of the type.  TYPE_XREF says we have
+   output it as a cross-reference only.
+   The file_number and type_number elements are used if DBX_USE_BINCL
+   is defined.  */
+
+struct typeinfo
+{
+  enum typestatus status;
+#ifdef DBX_USE_BINCL
+  int file_number;
+  int type_number;
+#endif
+};
+
+/* Vector recording information about C data types.
    When we first notice a data type (a tree node),
    we assign it a number using next_type_number.
-   That is its index in this vector.
-   The vector element says whether we have yet output
-   the definition of the type.  TYPE_XREF says we have
-   output it as a cross-reference only.  */
+   That is its index in this vector.  */
 
-enum typestatus *typevec;
+struct typeinfo *typevec;
 
 /* Number of elements of space allocated in `typevec'.  */
 
@@ -204,6 +249,29 @@ static int typevec_len;
 
 static int next_type_number;
 
+#ifdef DBX_USE_BINCL
+
+/* When using N_BINCL in dbx output, each type number is actually a
+   pair of the file number and the type number within the file.
+   This is a stack of input files.  */
+
+struct dbx_file
+{
+  struct dbx_file *next;
+  int file_number;
+  int next_type_number;
+};
+
+/* This is the top of the stack.  */
+
+static struct dbx_file *current_file;
+
+/* This is the next file number to use.  */
+
+static int next_file_number;
+
+#endif /* DBX_USE_BINCL */
+
 /* In dbx output, we must assign symbol-blocks id numbers
    in the order in which their beginnings are encountered.
    We output debugging info that refers to the beginning and
@@ -257,8 +325,11 @@ void dbxout_symbol ();
 static void dbxout_type_name ();
 static void dbxout_type ();
 static void dbxout_typedefs ();
+static void dbxout_symbol_name ();
+static void dbxout_symbol_location ();
 static void dbxout_prepare_symbol ();
 static void dbxout_finish_symbol ();
+static void dbxout_type_index ();
 static void dbxout_continue ();
 static void print_int_cst_octal ();
 static void print_octal ();
@@ -381,8 +452,8 @@ dbxout_init (asm_file, input_file_name, syms)
   asmfile = asm_file;
 
   typevec_len = 100;
-  typevec = (enum typestatus *) xmalloc (typevec_len * sizeof typevec[0]);
-  bzero (typevec, typevec_len * sizeof typevec[0]);
+  typevec = (struct typeinfo *) xmalloc (typevec_len * sizeof typevec[0]);
+  bzero ((char *) typevec, typevec_len * sizeof typevec[0]);
 
   /* Convert Ltext into the appropriate format for local labels in case
      the system doesn't insert underscores in front of user generated
@@ -392,16 +463,23 @@ dbxout_init (asm_file, input_file_name, syms)
   /* Put the current working directory in an N_SO symbol.  */
 #ifndef DBX_WORKING_DIRECTORY /* Only some versions of DBX want this,
                                 but GDB always does.  */
-  if (use_gdb_dbx_extensions)
+  if (use_gnu_debug_info_extensions)
 #endif
     {
-      if (cwd || (cwd = getpwd ()))
+      if (!cwd && (cwd = getpwd ()) && (!*cwd || cwd[strlen (cwd) - 1] != '/'))
+       {
+         char *wdslash = xmalloc (strlen (cwd) + sizeof (FILE_NAME_JOINER));
+         sprintf (wdslash, "%s%s", cwd, FILE_NAME_JOINER);
+         cwd = wdslash;
+       }
+      if (cwd)
        {
 #ifdef DBX_OUTPUT_MAIN_SOURCE_DIRECTORY
          DBX_OUTPUT_MAIN_SOURCE_DIRECTORY (asmfile, cwd);
 #else /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */
-         fprintf (asmfile, "%s \"%s/\",%d,0,0,%s\n", ASM_STABS_OP,
-                  cwd, N_SO, &ltext_label_name[1]);
+         fprintf (asmfile, "%s ", ASM_STABS_OP);
+         output_quoted_string (asmfile, cwd);
+         fprintf (asmfile, ",%d,0,0,%s\n", N_SO, &ltext_label_name[1]);
 #endif /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */
        }
     }
@@ -414,17 +492,34 @@ dbxout_init (asm_file, input_file_name, syms)
   /* We include outputting `Ltext:' here,
      because that gives you a way to override it.  */
   /* Used to put `Ltext:' before the reference, but that loses on sun 4.  */
-  fprintf (asmfile, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP, input_file_name,
+  fprintf (asmfile, "%s ", ASM_STABS_OP);
+  output_quoted_string (asmfile, input_file_name);
+  fprintf (asmfile, ",%d,0,0,%s\n", 
           N_SO, &ltext_label_name[1]);
   text_section ();
   ASM_OUTPUT_INTERNAL_LABEL (asmfile, "Ltext", 0);
 #endif /* no DBX_OUTPUT_MAIN_SOURCE_FILENAME */
 
+  /* Possibly output something to inform GDB that this compilation was by
+     GCC.  It's easier for GDB to parse it when after the N_SO's.  This
+     is used in Solaris 2.  */
+#ifdef ASM_IDENTIFY_GCC_AFTER_SOURCE
+  ASM_IDENTIFY_GCC_AFTER_SOURCE (asmfile);
+#endif
+
   lastfile = input_file_name;
 
   next_type_number = 1;
   next_block_number = 2;
 
+#ifdef DBX_USE_BINCL
+  current_file = (struct dbx_file *) xmalloc (sizeof *current_file);
+  current_file->next = NULL;
+  current_file->file_number = 0;
+  current_file->next_type_number = 1;
+  next_file_number = 1;
+#endif
+
   /* Make sure that types `int' and `char' have numbers 1 and 2.
      Definitions of other integer types will refer to those numbers.
      (Actually it should no longer matter what their numbers are.
@@ -466,6 +561,38 @@ dbxout_typedefs (syms)
     }
 }
 
+/* Change to reading from a new source file.  Generate a N_BINCL stab.  */
+
+void
+dbxout_start_new_source_file (filename)
+     char *filename;
+{
+#ifdef DBX_USE_BINCL
+  struct dbx_file *n = (struct dbx_file *) xmalloc (sizeof *n);
+
+  n->next = current_file;
+  n->file_number = next_file_number++;
+  n->next_type_number = 1;
+  current_file = n;
+  fprintf (asmfile, "%s \"%s\",%d,0,0,0\n", ASM_STABS_OP, filename, N_BINCL);
+#endif
+}
+
+/* Revert to reading a previous source file.  Generate a N_EINCL stab.  */
+
+void
+dbxout_resume_previous_source_file ()
+{
+#ifdef DBX_USE_BINCL
+  struct dbx_file *next;
+
+  fprintf (asmfile, "%s %d,0,0,0\n", ASM_STABN_OP, N_EINCL);
+  next = current_file->next;
+  free (current_file);
+  current_file = next;
+#endif
+}
+
 /* Output debugging info to FILE to switch to sourcefile FILENAME.  */
 
 void
@@ -480,14 +607,41 @@ dbxout_source_file (file, filename)
 #ifdef DBX_OUTPUT_SOURCE_FILENAME
       DBX_OUTPUT_SOURCE_FILENAME (file, filename);
 #else
-      ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
-      fprintf (file, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP,
-              filename, N_SOL, &ltext_label_name[1]);
+      ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext",
+                                  source_label_number);
+      fprintf (file, "%s ", ASM_STABS_OP);
+      output_quoted_string (file, filename);
+      fprintf (file, ",%d,0,0,%s\n", N_SOL, &ltext_label_name[1]);
+      if (current_function_decl != NULL_TREE
+         && DECL_SECTION_NAME (current_function_decl) != NULL_TREE)
+       ; /* Don't change section amid function.  */
+      else
+       text_section ();
+      ASM_OUTPUT_INTERNAL_LABEL (file, "Ltext", source_label_number);
+      source_label_number++;
 #endif
       lastfile = filename;
     }
 }
 
+/* Output a line number symbol entry into output stream FILE, 
+   for source file FILENAME and line number LINENO.  */
+
+void
+dbxout_source_line (file, filename, lineno)
+     FILE *file;
+     char *filename;
+     int lineno;
+{
+  dbxout_source_file (file, filename);
+
+#ifdef ASM_OUTPUT_SOURCE_LINE
+  ASM_OUTPUT_SOURCE_LINE (file, lineno);
+#else
+  fprintf (file, "\t%s %d,0,%d\n", ASM_STABD_OP, N_SLINE, lineno);
+#endif
+}
+
 /* At the end of compilation, finish writing the symbol table.
    Unless you define DBX_OUTPUT_MAIN_SOURCE_FILE_END, the default is
    to do nothing. */
@@ -502,6 +656,22 @@ dbxout_finish (file, filename)
 #endif /* DBX_OUTPUT_MAIN_SOURCE_FILE_END */
 }
 
+/* Output the index of a type.  */
+
+static void
+dbxout_type_index (type)
+     tree type;
+{
+#ifndef DBX_USE_BINCL
+  fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type));
+  CHARS (3);
+#else
+  struct typeinfo *t = &typevec[TYPE_SYMTAB_ADDRESS (type)];
+  fprintf (asmfile, "(%d,%d)", t->file_number, t->type_number);
+  CHARS (7);
+#endif
+}
+
 /* Continue a symbol-description that gets too big.
    End one symbol table entry with a double-backslash
    and start a new one, eventually producing something like
@@ -516,12 +686,12 @@ dbxout_continue ()
 #else
   fprintf (asmfile, "\\\\");
 #endif
-  dbxout_finish_symbol (0);
+  dbxout_finish_symbol (NULL_TREE);
   fprintf (asmfile, "%s \"", ASM_STABS_OP);
   current_sym_nchars = 0;
 }
 \f
-/* Subtroutine of `dbxout_type'.  Output the type fields of TYPE.
+/* Subroutine of `dbxout_type'.  Output the type fields of TYPE.
    This must be a separate function because anonymous unions require
    recursive calls.  */
 
@@ -530,45 +700,55 @@ dbxout_type_fields (type)
      tree type;
 {
   tree tem;
+  /* Output the name, type, position (in bits), size (in bits) of each
+     field.  */
   for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
     {
-      /* Output the name, type, position (in bits), size (in bits)
-        of each field.  */
-      if (DECL_NAME (tem) == NULL_TREE
-         && TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE)
-       dbxout_type_fields (TREE_TYPE (tem));
       /* Omit here local type decls until we know how to support them.  */
-      else if (TREE_CODE (tem) == TYPE_DECL)
+      if (TREE_CODE (tem) == TYPE_DECL)
+       continue;
+      /* Omit fields whose position or size are variable.  */
+      else if (TREE_CODE (tem) == FIELD_DECL
+              && (TREE_CODE (DECL_FIELD_BITPOS (tem)) != INTEGER_CST
+                  || TREE_CODE (DECL_SIZE (tem)) != INTEGER_CST))
        continue;
       /* Omit here the nameless fields that are used to skip bits.  */
-      else if (DECL_NAME (tem) != 0 && TREE_CODE (tem) != CONST_DECL)
+      else if (TREE_CODE (tem) != CONST_DECL)
        {
          /* Continue the line if necessary,
             but not before the first field.  */
          if (tem != TYPE_FIELDS (type))
            CONTIN;
 
-         if (use_gdb_dbx_extensions
+         if (use_gnu_debug_info_extensions
              && flag_minimal_debug
              && TREE_CODE (tem) == FIELD_DECL
              && DECL_VIRTUAL_P (tem)
              && DECL_ASSEMBLER_NAME (tem))
            {
              have_used_extensions = 1;
-             CHARS (3 + IDENTIFIER_LENGTH (DECL_NAME (TYPE_NAME (DECL_FCONTEXT (tem)))));
+             CHARS (3 + IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (tem)));
              fputs (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (tem)), asmfile);
-             dbxout_type (DECL_FCONTEXT (tem), 0);
+             dbxout_type (DECL_FCONTEXT (tem), 0, 0);
              fprintf (asmfile, ":");
-             dbxout_type (TREE_TYPE (tem), 0);
+             dbxout_type (TREE_TYPE (tem), 0, 0);
              fprintf (asmfile, ",%d;",
                       TREE_INT_CST_LOW (DECL_FIELD_BITPOS (tem)));
              continue;
            }
 
-         fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem)));
-         CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem)));
+         if (DECL_NAME (tem))
+           {
+             fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem)));
+             CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem)));
+           }
+         else
+           {
+             fprintf (asmfile, ":");
+             CHARS (2);
+           }
 
-         if (use_gdb_dbx_extensions
+         if (use_gnu_debug_info_extensions
              && (TREE_PRIVATE (tem) || TREE_PROTECTED (tem)
                  || TREE_CODE (tem) != FIELD_DECL))
            {
@@ -583,25 +763,14 @@ dbxout_type_fields (type)
          dbxout_type ((TREE_CODE (tem) == FIELD_DECL
                        && DECL_BIT_FIELD_TYPE (tem))
                       ? DECL_BIT_FIELD_TYPE (tem)
-                      : TREE_TYPE (tem), 0);
+                      : TREE_TYPE (tem), 0, 0);
 
          if (TREE_CODE (tem) == VAR_DECL)
            {
-             if (TREE_STATIC (tem) && use_gdb_dbx_extensions)
+             if (TREE_STATIC (tem) && use_gnu_debug_info_extensions)
                {
                  char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (tem));
                  have_used_extensions = 1;
-
-#if 0 /* ??? Comment below makes it clear this is unacceptable.  */
-                 /* Adding 1 here only works on systems
-                    which flush an initial underscore from
-                    the .stabs entry.  This loses for static names
-                    which have an initial leading '_' on systems which
-                    don't use leading underscores.  */
-                 if (name[0] == '_')
-                   name += 1;
-#endif
-
                  fprintf (asmfile, ":%s;", name);
                  CHARS (strlen (name));
                }
@@ -617,15 +786,12 @@ dbxout_type_fields (type)
                       TREE_INT_CST_LOW (DECL_FIELD_BITPOS (tem)),
                       TREE_INT_CST_LOW (DECL_SIZE (tem)));
            }
-         else
-           /* This has yet to be implemented.  */
-           abort ();
          CHARS (23);
        }
     }
 }
 \f
-/* Subtroutine of `dbxout_type_methods'.  Output debug info about the
+/* Subroutine of `dbxout_type_methods'.  Output debug info about the
    method described DECL.  DEBUG_NAME is an encoding of the method's
    type signature.  ??? We may be able to do without DEBUG_NAME altogether
    now.  */
@@ -635,13 +801,13 @@ dbxout_type_method_1 (decl, debug_name)
      tree decl;
      char *debug_name;
 {
-  tree firstarg = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)));
   char c1 = 'A', c2;
 
   if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
     c2 = '?';
   else /* it's a METHOD_TYPE.  */
     {
+      tree firstarg = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)));
       /* A for normal functions.
         B for `const' member functions.
         C for `volatile' member functions.
@@ -665,7 +831,7 @@ dbxout_type_method_1 (decl, debug_name)
     {
       fprintf (asmfile, "%d;",
               TREE_INT_CST_LOW (DECL_VINDEX (decl)));
-      dbxout_type (DECL_CONTEXT (decl), 0);
+      dbxout_type (DECL_CONTEXT (decl), 0, 0);
       fprintf (asmfile, ";");
       CHARS (8);
     }
@@ -679,111 +845,60 @@ dbxout_type_methods (type)
      register tree type;
 {
   /* C++: put out the method names and their parameter lists */
-  tree ctor_name;
   tree methods = TYPE_METHODS (type);
+  tree type_encoding;
   register tree fndecl;
   register tree last;
+  char formatted_type_identifier_length[16];
   register int type_identifier_length;
 
   if (methods == NULL_TREE)
     return;
 
-  ctor_name = DECL_NAME (TYPE_NAME (type));
-  type_identifier_length = IDENTIFIER_LENGTH (ctor_name);
-  if (TREE_CODE (methods) == FUNCTION_DECL)
-    fndecl = methods;
-  else if (TREE_VEC_ELT (methods, 0) != NULL_TREE)
-    fndecl = TREE_VEC_ELT (methods, 0);
-  else fndecl = TREE_VEC_ELT (methods, 1);
-
-  if (TREE_CODE (type) == RECORD_TYPE && DECL_NAME (fndecl) == ctor_name)
-    {
-      tree ctor = fndecl;
-      tree dtor;
-
-      /* Destructors lie in a special place.
-         n.b.  TYPE_HAS_DESTRUCTOR == TYPE_LANG_FLAG_2 */
-      if (TYPE_LANG_FLAG_2 (type))
-       {
-         dtor = fndecl;
-         fndecl = ctor = TREE_CHAIN (dtor);
-       }
-      else
-       dtor = NULL_TREE;
-
-      CHARS (2);
-
-      if (ctor)
-       {
-         int need_prefix = 1;
-
-         while (ctor)
-           {
-             /* Output the name of the field (after overloading), as
-                well as the name of the field before overloading, along
-                with its parameter list.  */
-             char *debug_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (ctor));
-             int old_minimal_debug = flag_minimal_debug;
-
-             CONTIN;
+  type_encoding = DECL_NAME (TYPE_NAME (type));
 
-             if (DECL_NAME (ctor) == ctor_name && ! DECL_IGNORED_P (ctor))
-               {
-                 if (need_prefix)
-                   {
-                     fprintf (asmfile, "%s::", IDENTIFIER_POINTER (DECL_NAME (ctor)));
-                     CHARS (IDENTIFIER_LENGTH (DECL_NAME (ctor)) + 3);
-                     need_prefix = 0;
-                   }
-
-                 if (ctor == dtor)
-                   /* Always output destructors with full information.  */
-                   flag_minimal_debug = 0;
-
-                 dbxout_type (TREE_TYPE (ctor), 0);
-                 flag_minimal_debug = old_minimal_debug;
-
-                 if (flag_minimal_debug && ctor != dtor)
-                   {
-                     /* Cut down on debugging information by not outputting
-                        the parts of the name we can just as easily
-                        have the debugger figure out.  */
+#if 0
+  /* C++: Template classes break some assumptions made by this code about
+     the class names, constructor names, and encodings for assembler
+     label names.  For now, disable output of dbx info for them.  */
+  {
+    char *ptr = IDENTIFIER_POINTER (type_encoding);
+    /* This should use index.  (mrs) */
+    while (*ptr && *ptr != '<') ptr++;
+    if (*ptr != 0)
+      {
+       static int warned;
+       if (!warned)
+         {
+           warned = 1;
+#ifdef HAVE_TEMPLATES
+           if (warn_template_debugging)
+             warning ("dbx info for template class methods not yet supported");
+#endif
+         }
+       return;
+      }
+  }
+#endif
 
-                     /* Get past '__'.  */
-                     debug_name += 2;
-                     /* Get past const and volatile qualifiers.  */
-                     while (*debug_name == 'C' || *debug_name == 'V')
-                       debug_name++;
-                     /* Get past numeric type length prefix.  */
-                     while (*debug_name >= '0' && *debug_name <= '9')
-                       debug_name++;
-                     /* Get past type of `this'.  */
-                     debug_name += type_identifier_length;
-                   }
-                 dbxout_type_method_1 (ctor, debug_name);
-               }
+  type_identifier_length = IDENTIFIER_LENGTH (type_encoding);
 
-             if (ctor == dtor)
-               break;
+  sprintf(formatted_type_identifier_length, "%d", type_identifier_length);
 
-             ctor = TREE_CHAIN (ctor);
-             if (ctor == NULL_TREE || DECL_NAME (ctor) != ctor_name)
-               {
-                 fndecl = ctor;
-                 ctor = dtor;
-               }
-           }
-         if (! need_prefix)
-           putc (';', asmfile);
-       }
-    }
+  if (TREE_CODE (methods) == FUNCTION_DECL)
+    fndecl = methods;
+  else if (TREE_VEC_ELT (methods, 0) != NULL_TREE)
+    fndecl = TREE_VEC_ELT (methods, 0);
+  else
+    fndecl = TREE_VEC_ELT (methods, 1);
 
   while (fndecl)
     {
       tree name = DECL_NAME (fndecl);
-      fprintf (asmfile, "%s::", IDENTIFIER_POINTER (name));
-      CHARS (IDENTIFIER_LENGTH (name) + 3);
+      int need_prefix = 1;
 
+      /* Group together all the methods for the same operation.
+        These differ in the types of the arguments.  */
       for (last = NULL_TREE;
           fndecl && (last == NULL_TREE || DECL_NAME (fndecl) == DECL_NAME (last));
           fndecl = TREE_CHAIN (fndecl))
@@ -791,28 +906,129 @@ dbxout_type_methods (type)
           well as the name of the field before overloading, along
           with its parameter list */
        {
+         /* This is the "mangled" name of the method.
+            It encodes the argument types.  */
          char *debug_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
+         int show_arg_types = 0;
 
          CONTIN;
 
          last = fndecl;
-         dbxout_type (TREE_TYPE (fndecl), 0);
+
+         if (DECL_IGNORED_P (fndecl))
+           continue;
+
          if (flag_minimal_debug)
            {
-             debug_name += IDENTIFIER_LENGTH (DECL_NAME (fndecl)) + 2;
-             /* Get past const and volatile qualifiers.  */
-             while (*debug_name == 'C' || *debug_name == 'V')
-               debug_name++;
-             while (*debug_name >= '0' && *debug_name <= '9')
-               debug_name++;
-             debug_name += type_identifier_length;
+             char marker;
+
+             /* We can't optimize a method which uses an anonymous
+                 class, because the debugger will not be able to
+                 associate the arbitrary class name with the actual
+                 class.  */
+#ifndef NO_DOLLAR_IN_LABEL
+             marker = '$';
+#else
+             marker = '.';
+#endif
+             if (strchr (debug_name, marker))
+               show_arg_types = 1;
+             /* Detect ordinary methods because their mangled names
+                start with the operation name.  */
+             else if (!strncmp (IDENTIFIER_POINTER (name), debug_name,
+                                IDENTIFIER_LENGTH (name)))
+               {
+                 debug_name += IDENTIFIER_LENGTH (name);
+                 if (debug_name[0] == '_' && debug_name[1] == '_')
+                   {
+                     char *method_name = debug_name + 2;
+                     char *length_ptr = formatted_type_identifier_length;
+                     /* Get past const and volatile qualifiers.  */
+                     while (*method_name == 'C' || *method_name == 'V')
+                       method_name++;
+                     /* Skip digits for length of type_encoding. */
+                     while (*method_name == *length_ptr && *length_ptr)
+                         length_ptr++, method_name++;
+                     if (! strncmp (method_name,
+                                    IDENTIFIER_POINTER (type_encoding),
+                                    type_identifier_length))
+                       method_name += type_identifier_length;
+                     debug_name = method_name;
+                   }
+               }
+             /* Detect constructors by their style of name mangling.  */
+             else if (debug_name[0] == '_' && debug_name[1] == '_')
+               {
+                 char *ctor_name = debug_name + 2;
+                 char *length_ptr = formatted_type_identifier_length;
+                 while (*ctor_name == 'C' || *ctor_name == 'V')
+                   ctor_name++;
+                 /* Skip digits for length of type_encoding. */
+                 while (*ctor_name == *length_ptr && *length_ptr)
+                     length_ptr++, ctor_name++;
+                 if (!strncmp (IDENTIFIER_POINTER (type_encoding), ctor_name,
+                               type_identifier_length))
+                   debug_name = ctor_name + type_identifier_length;
+               }
+             /* The other alternative is a destructor.  */
+             else
+               show_arg_types = 1;
+
+             /* Output the operation name just once, for the first method
+                that we output.  */
+             if (need_prefix)
+               {
+                 fprintf (asmfile, "%s::", IDENTIFIER_POINTER (name));
+                 CHARS (IDENTIFIER_LENGTH (name) + 2);
+                 need_prefix = 0;
+               }
            }
+
+         dbxout_type (TREE_TYPE (fndecl), 0, show_arg_types);
+
          dbxout_type_method_1 (fndecl, debug_name);
        }
-      putc (';', asmfile);
-      CHARS (1);
+      if (!need_prefix)
+       {
+          putc (';', asmfile);
+         CHARS (1);
+       }
     }
 }
+
+/* Emit a "range" type specification, which has the form:
+   "r<index type>;<lower bound>;<upper bound>;".
+   TYPE is an INTEGER_TYPE. */
+
+static void
+dbxout_range_type (type)
+     tree type;
+{
+  fprintf (asmfile, "r");
+  if (TREE_TYPE (type))
+    dbxout_type (TREE_TYPE (type), 0, 0);
+  else if (TREE_CODE (type) != INTEGER_TYPE)
+    dbxout_type (type, 0, 0); /* E.g. Pascal's ARRAY [BOOLEAN] of INTEGER */
+  else
+    {
+      /* Traditionally, we made sure 'int' was type 1, and builtin types
+        were defined to be sub-ranges of int.  Unfortunately, this
+        does not allow us to distinguish true sub-ranges from integer
+        types.  So, instead we define integer (non-sub-range) types as
+        sub-ranges of themselves. */
+      dbxout_type_index (type);
+    }
+  if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST)
+    fprintf (asmfile, ";%d", 
+            TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)));
+  else
+    fprintf (asmfile, ";0");
+  if (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST)
+    fprintf (asmfile, ";%d;", 
+            TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)));
+  else
+    fprintf (asmfile, ";-1;");
+}
 \f
 /* Output a reference to a type.  If the type has not yet been
    described in the dbx output, output its definition now.
@@ -822,26 +1038,32 @@ dbxout_type_methods (type)
    If FULL is nonzero, and the type has been described only with
    a forward-reference, output the definition now.
    If FULL is zero in this case, just refer to the forward-reference
-   using the number previously allocated.  */
+   using the number previously allocated.
+
+   If SHOW_ARG_TYPES is nonzero, we output a description of the argument
+   types for a METHOD_TYPE.  */
 
 static void
-dbxout_type (type, full)
+dbxout_type (type, full, show_arg_types)
      tree type;
      int full;
+     int show_arg_types;
 {
   register tree tem;
+  static int anonymous_type_number = 0;
 
   /* If there was an input error and we don't really have a type,
      avoid crashing and write something that is at least valid
      by assuming `int'.  */
   if (type == error_mark_node)
     type = integer_type_node;
-  else
+  else if (!(TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+            && DECL_ORIGINAL_TYPE (TYPE_NAME (type))))
     {
       type = TYPE_MAIN_VARIANT (type);
       if (TYPE_NAME (type)
          && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
-         && DECL_IGNORED_P (TYPE_NAME (type)))
+         && TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (type)))
        full = 0;
     }
 
@@ -854,15 +1076,24 @@ dbxout_type (type, full)
 
       if (next_type_number == typevec_len)
        {
-         typevec = (enum typestatus *) xrealloc (typevec, typevec_len * 2 * sizeof typevec[0]);
-         bzero (typevec + typevec_len, typevec_len * sizeof typevec[0]);
+         typevec =
+           (struct typeinfo *) xrealloc (typevec,
+                                         typevec_len * 2 * sizeof typevec[0]);
+         bzero ((char *) (typevec + typevec_len),
+                typevec_len * sizeof typevec[0]);
          typevec_len *= 2;
        }
+
+#ifdef DBX_USE_BINCL
+      typevec[TYPE_SYMTAB_ADDRESS (type)].file_number =
+       current_file->file_number;
+      typevec[TYPE_SYMTAB_ADDRESS (type)].type_number =
+       current_file->next_type_number++;
+#endif
     }
 
   /* Output the number of this type, to refer to it.  */
-  fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type));
-  CHARS (3);
+  dbxout_type_index (type);
 
 #ifdef DBX_TYPE_DEFINED
   if (DBX_TYPE_DEFINED (type))
@@ -872,12 +1103,18 @@ dbxout_type (type, full)
   /* If this type's definition has been output or is now being output,
      that is all.  */
 
-  switch (typevec[TYPE_SYMTAB_ADDRESS (type)])
+  switch (typevec[TYPE_SYMTAB_ADDRESS (type)].status)
     {
     case TYPE_UNSEEN:
       break;
     case TYPE_XREF:
-      if (! full)
+      /* If we have already had a cross reference,
+        and either that's all we want or that's the best we could do,
+        don't repeat the cross reference.
+        Sun dbx crashes if we do.  */
+      if (! full || TYPE_SIZE (type) == 0
+         /* No way in DBX fmt to describe a variable size.  */
+         || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
        return;
       break;
     case TYPE_DEFINED:
@@ -887,14 +1124,24 @@ dbxout_type (type, full)
 #ifdef DBX_NO_XREFS
   /* For systems where dbx output does not allow the `=xsNAME:' syntax,
      leave the type-number completely undefined rather than output
-     a cross-reference.  */
-  if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
-      || TREE_CODE (type) == ENUMERAL_TYPE)
-
-    if ((TYPE_NAME (type) != 0 && !full)
-       || TYPE_SIZE (type) == 0)
+     a cross-reference.  If we have already used GNU debug info extensions,
+     then it is OK to output a cross reference.  This is necessary to get
+     proper C++ debug output.  */
+  if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
+       || TREE_CODE (type) == QUAL_UNION_TYPE
+       || TREE_CODE (type) == ENUMERAL_TYPE)
+      && ! use_gnu_debug_info_extensions)
+    /* We must use the same test here as we use twice below when deciding
+       whether to emit a cross-reference.  */
+    if ((TYPE_NAME (type) != 0
+        && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+              && DECL_IGNORED_P (TYPE_NAME (type)))
+        && !full)
+       || TYPE_SIZE (type) == 0
+       /* No way in DBX fmt to describe a variable size.  */
+       || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
       {
-       typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
+       typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF;
        return;
       }
 #endif
@@ -907,7 +1154,14 @@ dbxout_type (type, full)
   /* Mark it as defined, so that if it is self-referent
      we will not get into an infinite recursion of definitions.  */
 
-  typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_DEFINED;
+  typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_DEFINED;
+
+  if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+      && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+    { 
+      dbxout_type (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), 0, 0);
+      return;
+    }
 
   switch (TREE_CODE (type))
     {
@@ -918,79 +1172,174 @@ dbxout_type (type, full)
         without saying what it is.  The debugger will make it
         a void type when the reference is seen, and nothing will
         ever override that default.  */
-      fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type));
-      CHARS (3);
+      dbxout_type_index (type);
       break;
 
     case INTEGER_TYPE:
       if (type == char_type_node && ! TREE_UNSIGNED (type))
-       /* Output the type `char' as a subrange of itself!
-          I don't understand this definition, just copied it
-          from the output of pcc.
-          This used to use `r2' explicitly and we used to
-          take care to make sure that `char' was type number 2.  */
-       fprintf (asmfile, "r%d;0;127;", TYPE_SYMTAB_ADDRESS (type));
-#ifdef WINNING_GDB
-      else if (TYPE_PRECISION (type) > BITS_PER_WORD)
+       {
+         /* Output the type `char' as a subrange of itself!
+            I don't understand this definition, just copied it
+            from the output of pcc.
+            This used to use `r2' explicitly and we used to
+            take care to make sure that `char' was type number 2.  */
+         fprintf (asmfile, "r");
+         dbxout_type_index (type);
+         fprintf (asmfile, ";0;127;");
+       }
+      else if (use_gnu_debug_info_extensions
+              && (TYPE_PRECISION (type) > TYPE_PRECISION (integer_type_node)
+                  || TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT))
        {
          /* This used to say `r1' and we used to take care
             to make sure that `int' was type number 1.  */
-         fprintf (asmfile, "r%d;", TYPE_SYMTAB_ADDRESS (integer_type_node));
+         fprintf (asmfile, "r");
+         dbxout_type_index (integer_type_node);
+         fprintf (asmfile, ";");
          print_int_cst_octal (TYPE_MIN_VALUE (type));
          fprintf (asmfile, ";");
          print_int_cst_octal (TYPE_MAX_VALUE (type));
          fprintf (asmfile, ";");
        }
-#endif
-      else
-       /* Output other integer types as subranges of `int'.  */
-       /* This used to say `r1' and we used to take care
-          to make sure that `int' was type number 1.  */
-       fprintf (asmfile, "r%d;%d;%d;",
-                TYPE_SYMTAB_ADDRESS (integer_type_node),
-                TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)),
-                TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)));
-      CHARS (25);
+      else /* Output other integer types as subranges of `int'.  */
+       dbxout_range_type (type);
+      CHARS (22);
       break;
 
     case REAL_TYPE:
       /* This used to say `r1' and we used to take care
         to make sure that `int' was type number 1.  */
-      fprintf (asmfile, "r%d;%d;0;", TYPE_SYMTAB_ADDRESS (integer_type_node),
-              TREE_INT_CST_LOW (size_in_bytes (type)));
-      CHARS (16);
+      fprintf (asmfile, "r");
+      dbxout_type_index (integer_type_node);
+      fprintf (asmfile, ";%d;0;", int_size_in_bytes (type));
+      CHARS (13);
+      break;
+
+    case CHAR_TYPE:
+      if (use_gnu_debug_info_extensions)
+       fprintf (asmfile, "@s%d;-20;",
+                BITS_PER_UNIT * int_size_in_bytes (type));
+      else
+       {
+         /* Output the type `char' as a subrange of itself.
+            That is what pcc seems to do.  */
+         fprintf (asmfile, "r");
+         dbxout_type_index (char_type_node);
+         fprintf (asmfile, ";0;%d;", TREE_UNSIGNED (type) ? 255 : 127);
+       }
+      CHARS (9);
+      break;
+
+    case BOOLEAN_TYPE:
+      if (use_gnu_debug_info_extensions)
+       fprintf (asmfile, "@s%d;-16;",
+                BITS_PER_UNIT * int_size_in_bytes (type));
+      else /* Define as enumeral type (False, True) */
+       fprintf (asmfile, "eFalse:0,True:1,;");
+      CHARS (17);
+      break;
+
+    case FILE_TYPE:
+      putc ('d', asmfile);
+      CHARS (1);
+      dbxout_type (TREE_TYPE (type), 0, 0);
+      break;
+
+    case COMPLEX_TYPE:
+      /* Differs from the REAL_TYPE by its new data type number */
+
+      if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+       {
+         fprintf (asmfile, "r");
+         dbxout_type_index (type);
+         fprintf (asmfile, ";%d;0;",
+                  int_size_in_bytes (TREE_TYPE (type)));
+         CHARS (12);           /* The number is probably incorrect here.  */
+       }
+      else
+       {
+         /* Output a complex integer type as a structure,
+            pending some other way to do it.  */
+         fprintf (asmfile, "s%d", int_size_in_bytes (type));
+
+         fprintf (asmfile, "real:");
+         CHARS (10);
+         dbxout_type (TREE_TYPE (type), 0, 0);
+         fprintf (asmfile, ",%d,%d;",
+                  0, TYPE_PRECISION (TREE_TYPE (type)));
+         CHARS (8);
+         fprintf (asmfile, "imag:");
+         CHARS (5);
+         dbxout_type (TREE_TYPE (type), 0, 0);
+         fprintf (asmfile, ",%d,%d;;",
+                  TYPE_PRECISION (TREE_TYPE (type)),
+                  TYPE_PRECISION (TREE_TYPE (type)));
+         CHARS (9);
+       }
+      break;
+
+    case SET_TYPE:
+      if (use_gnu_debug_info_extensions)
+       {
+         have_used_extensions = 1;
+         fprintf (asmfile, "@s%d;",
+                  BITS_PER_UNIT * int_size_in_bytes (type));
+         /* Check if a bitstring type, which in Chill is
+            different from a [power]set. */
+         if (TYPE_STRING_FLAG (type))
+           fprintf (asmfile, "@S;");
+       }
+      putc ('S', asmfile);
+      CHARS (1);
+      dbxout_type (TYPE_DOMAIN (type), 0, 0);
       break;
 
     case ARRAY_TYPE:
       /* Output "a" followed by a range type definition
         for the index type of the array
         followed by a reference to the target-type.
-        ar1;0;N;M for an array of type M and size N.  */
-      /* This used to say `r1' and we used to take care
-        to make sure that `int' was type number 1.  */
-      fprintf (asmfile, "ar%d;0;%d;", TYPE_SYMTAB_ADDRESS (integer_type_node),
-
-              (TYPE_DOMAIN (type)
-               ? TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
-               : -1));
-      CHARS (17);
-      dbxout_type (TREE_TYPE (type), 0);
+        ar1;0;N;M for a C array of type M and size N+1.  */
+      /* Check if a character string type, which in Chill is
+        different from an array of characters. */
+      if (TYPE_STRING_FLAG (type) && use_gnu_debug_info_extensions)
+       {
+         have_used_extensions = 1;
+         fprintf (asmfile, "@S;");
+       }
+      tem = TYPE_DOMAIN (type);
+      if (tem == NULL)
+       {
+         fprintf (asmfile, "ar");
+         dbxout_type_index (integer_type_node);
+         fprintf (asmfile, ";0;-1;");
+       }
+      else
+       {
+         fprintf (asmfile, "a");
+         dbxout_range_type (tem);
+       }
+      CHARS (14);
+      dbxout_type (TREE_TYPE (type), 0, 0);
       break;
 
     case RECORD_TYPE:
     case UNION_TYPE:
+    case QUAL_UNION_TYPE:
       {
        int i, n_baseclasses = 0;
 
        if (TYPE_BINFO (type) != 0 && TYPE_BINFO_BASETYPES (type) != 0)
          n_baseclasses = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type));
 
-       /* Output a structure type.  */
+       /* Output a structure type.  We must use the same test here as we
+          use in the DBX_NO_XREFS case above.  */
        if ((TYPE_NAME (type) != 0
             && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
                   && DECL_IGNORED_P (TYPE_NAME (type)))
             && !full)
-           || TYPE_SIZE (type) == 0)
+           || TYPE_SIZE (type) == 0
+           /* No way in DBX fmt to describe a variable size.  */
+           || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
          {
            /* If the type is just a cross reference, output one
               and mark the type as partially described.
@@ -1001,29 +1350,27 @@ dbxout_type (type, full)
               and let the definition come when the name is defined.  */
            fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "xs" : "xu");
            CHARS (3);
-#if 0                          /* This assertion is legitimately false in C++.  */
+#if 0 /* This assertion is legitimately false in C++.  */
            /* We shouldn't be outputting a reference to a type before its
               definition unless the type has a tag name.
               A typedef name without a tag name should be impossible.  */
            if (TREE_CODE (TYPE_NAME (type)) != IDENTIFIER_NODE)
              abort ();
 #endif
-           dbxout_type_name (type);
+           if (TYPE_NAME (type) != 0)
+             dbxout_type_name (type);
+           else
+             fprintf (asmfile, "$$%d", anonymous_type_number++);
            fprintf (asmfile, ":");
-           typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
+           typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF;
            break;
          }
-       tem = size_in_bytes (type);
-
-       /* The code below assumes the size is an integer constant.  */
-       if (TREE_CODE (tem) != INTEGER_CST)
-         abort ();
 
        /* Identify record or union, and print its size.  */
        fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "s%d" : "u%d",
-                TREE_INT_CST_LOW (tem));
+                int_size_in_bytes (type));
 
-       if (use_gdb_dbx_extensions)
+       if (use_gnu_debug_info_extensions)
          {
            if (n_baseclasses)
              {
@@ -1035,7 +1382,7 @@ dbxout_type (type, full)
        for (i = 0; i < n_baseclasses; i++)
          {
            tree child = TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (type)), i);
-           if (use_gdb_dbx_extensions)
+           if (use_gnu_debug_info_extensions)
              {
                have_used_extensions = 1;
                putc (TREE_VIA_VIRTUAL (child) ? '1'
@@ -1047,7 +1394,7 @@ dbxout_type (type, full)
                fprintf (asmfile, "%d,",
                         TREE_INT_CST_LOW (BINFO_OFFSET (child)) * BITS_PER_UNIT);
                CHARS (15);
-               dbxout_type (BINFO_TYPE (child), 0);
+               dbxout_type (BINFO_TYPE (child), 0, 0);
                putc (';', asmfile);
              }
            else
@@ -1056,7 +1403,7 @@ dbxout_type (type, full)
                   which have the same names at the types they hold.  */
                dbxout_type_name (BINFO_TYPE (child));
                putc (':', asmfile);
-               dbxout_type (BINFO_TYPE (child), full);
+               dbxout_type (BINFO_TYPE (child), full, 0);
                fprintf (asmfile, ",%d,%d;",
                         TREE_INT_CST_LOW (BINFO_OFFSET (child)) * BITS_PER_UNIT,
                         TREE_INT_CST_LOW (DECL_SIZE (TYPE_NAME (BINFO_TYPE (child)))) * BITS_PER_UNIT);
@@ -1069,14 +1416,14 @@ dbxout_type (type, full)
 
       /* Write out the field declarations.  */
       dbxout_type_fields (type);
-      if (use_gdb_dbx_extensions && TYPE_METHODS (type) != NULL_TREE)
+      if (use_gnu_debug_info_extensions && TYPE_METHODS (type) != NULL_TREE)
        {
          have_used_extensions = 1;
          dbxout_type_methods (type);
        }
       putc (';', asmfile);
 
-      if (use_gdb_dbx_extensions && TREE_CODE (type) == RECORD_TYPE
+      if (use_gnu_debug_info_extensions && TREE_CODE (type) == RECORD_TYPE
          /* Avoid the ~ if we don't really need it--it confuses dbx.  */
          && TYPE_VFIELD (type))
        {
@@ -1092,7 +1439,7 @@ dbxout_type (type, full)
          if (TYPE_VFIELD (type))
            {
              putc ('%', asmfile);
-             dbxout_type (DECL_FCONTEXT (TYPE_VFIELD (type)), 0);
+             dbxout_type (DECL_FCONTEXT (TYPE_VFIELD (type)), 0, 0);
            }
          putc (';', asmfile);
          CHARS (3);
@@ -1100,57 +1447,81 @@ dbxout_type (type, full)
       break;
 
     case ENUMERAL_TYPE:
-      if ((TYPE_NAME (type) != 0 && !full
-          && (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
-              && ! DECL_IGNORED_P (TYPE_NAME (type))))
+      /* We must use the same test here as we use in the DBX_NO_XREFS case
+        above.  We simplify it a bit since an enum will never have a variable
+        size.  */
+      if ((TYPE_NAME (type) != 0
+          && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+                && DECL_IGNORED_P (TYPE_NAME (type)))
+          && !full)
          || TYPE_SIZE (type) == 0)
        {
          fprintf (asmfile, "xe");
          CHARS (3);
          dbxout_type_name (type);
-         typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
+         typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF;
          fprintf (asmfile, ":");
          return;
        }
+#ifdef DBX_OUTPUT_ENUM
+      DBX_OUTPUT_ENUM (asmfile, type);
+#else
+      if (use_gnu_debug_info_extensions
+         && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node))
+       fprintf (asmfile, "@s%d;", TYPE_PRECISION (type));
       putc ('e', asmfile);
       CHARS (1);
       for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem))
        {
-         fprintf (asmfile, "%s:%d,", IDENTIFIER_POINTER (TREE_PURPOSE (tem)),
-                  TREE_INT_CST_LOW (TREE_VALUE (tem)));
-         CHARS (11 + IDENTIFIER_LENGTH (TREE_PURPOSE (tem)));
+         fprintf (asmfile, "%s:", IDENTIFIER_POINTER (TREE_PURPOSE (tem)));
+         if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == 0)
+           fprintf (asmfile, "%lu",
+                    (unsigned long) TREE_INT_CST_LOW (TREE_VALUE (tem)));
+         else if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == -1
+                  && TREE_INT_CST_LOW (TREE_VALUE (tem)) < 0)
+           fprintf (asmfile, "%ld",
+                    (long) TREE_INT_CST_LOW (TREE_VALUE (tem)));
+         else
+           print_int_cst_octal (TREE_VALUE (tem));
+         fprintf (asmfile, ",");
+         CHARS (20 + IDENTIFIER_LENGTH (TREE_PURPOSE (tem)));
          if (TREE_CHAIN (tem) != 0)
            CONTIN;
        }
       putc (';', asmfile);
       CHARS (1);
+#endif
       break;
 
     case POINTER_TYPE:
       putc ('*', asmfile);
       CHARS (1);
-      dbxout_type (TREE_TYPE (type), 0);
+      dbxout_type (TREE_TYPE (type), 0, 0);
       break;
 
     case METHOD_TYPE:
-      if (use_gdb_dbx_extensions)
+      if (use_gnu_debug_info_extensions)
        {
          have_used_extensions = 1;
          putc ('#', asmfile);
          CHARS (1);
-         if (flag_minimal_debug)
+         if (flag_minimal_debug && !show_arg_types)
            {
+             /* Normally, just output the return type.
+                The argument types are encoded in the method name.  */
              putc ('#', asmfile);
-             dbxout_type (TREE_TYPE (type), 0);
+             dbxout_type (TREE_TYPE (type), 0, 0);
              putc (';', asmfile);
              CHARS (1);
            }
          else
            {
-             dbxout_type (TYPE_METHOD_BASETYPE (type), 0);
+             /* When outputting destructors, we need to write
+                the argument types out longhand.  */
+             dbxout_type (TYPE_METHOD_BASETYPE (type), 0, 0);
              putc (',', asmfile);
              CHARS (1);
-             dbxout_type (TREE_TYPE (type), 0);
+             dbxout_type (TREE_TYPE (type), 0, 0);
              dbxout_args (TYPE_ARG_TYPES (type));
              putc (';', asmfile);
              CHARS (1);
@@ -1159,41 +1530,41 @@ dbxout_type (type, full)
       else
        {
          /* Treat it as a function type.  */
-         dbxout_type (TREE_TYPE (type), 0);
+         dbxout_type (TREE_TYPE (type), 0, 0);
        }
       break;
 
     case OFFSET_TYPE:
-      if (use_gdb_dbx_extensions)
+      if (use_gnu_debug_info_extensions)
        {
          have_used_extensions = 1;
          putc ('@', asmfile);
          CHARS (1);
-         dbxout_type (TYPE_OFFSET_BASETYPE (type), 0);
+         dbxout_type (TYPE_OFFSET_BASETYPE (type), 0, 0);
          putc (',', asmfile);
          CHARS (1);
-         dbxout_type (TREE_TYPE (type), 0);
+         dbxout_type (TREE_TYPE (type), 0, 0);
        }
       else
        {
          /* Should print as an int, because it is really
             just an offset.  */
-         dbxout_type (integer_type_node, 0);
+         dbxout_type (integer_type_node, 0, 0);
        }
       break;
 
     case REFERENCE_TYPE:
-      if (use_gdb_dbx_extensions)
+      if (use_gnu_debug_info_extensions)
        have_used_extensions = 1;
-      putc (use_gdb_dbx_extensions ? '&' : '*', asmfile);
+      putc (use_gnu_debug_info_extensions ? '&' : '*', asmfile);
       CHARS (1);
-      dbxout_type (TREE_TYPE (type), 0);
+      dbxout_type (TREE_TYPE (type), 0, 0);
       break;
 
     case FUNCTION_TYPE:
       putc ('f', asmfile);
       CHARS (1);
-      dbxout_type (TREE_TYPE (type), 0);
+      dbxout_type (TREE_TYPE (type), 0, 0);
       break;
 
     default:
@@ -1208,32 +1579,49 @@ static void
 print_int_cst_octal (c)
      tree c;
 {
-  unsigned int high = TREE_INT_CST_HIGH (c);
-  unsigned int low = TREE_INT_CST_LOW (c);
-  int excess = (3 - (HOST_BITS_PER_INT % 3));
+  unsigned HOST_WIDE_INT high = TREE_INT_CST_HIGH (c);
+  unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (c);
+  int excess = (3 - (HOST_BITS_PER_WIDE_INT % 3));
+  int width = TYPE_PRECISION (TREE_TYPE (c));
+
+  /* GDB wants constants with no extra leading "1" bits, so
+     we need to remove any sign-extension that might be
+     present.  */
+  if (width == HOST_BITS_PER_WIDE_INT * 2)
+    ;
+  else if (width > HOST_BITS_PER_WIDE_INT)
+    high &= (((HOST_WIDE_INT) 1 << (width - HOST_BITS_PER_WIDE_INT)) - 1);
+  else if (width == HOST_BITS_PER_WIDE_INT)
+    high = 0;
+  else
+    high = 0, low &= (((HOST_WIDE_INT) 1 << width) - 1);
 
   fprintf (asmfile, "0");
 
   if (excess == 3)
     {
-      print_octal (high, HOST_BITS_PER_INT / 3);
-      print_octal (low, HOST_BITS_PER_INT / 3);
+      print_octal (high, HOST_BITS_PER_WIDE_INT / 3);
+      print_octal (low, HOST_BITS_PER_WIDE_INT / 3);
     }
   else
     {
-      unsigned int beg = high >> excess;
-      unsigned int middle
-       = ((high & ((1 << excess) - 1)) << (3 - excess)
-          | (low >> (HOST_BITS_PER_INT / 3 * 3)));
-      unsigned int end = low & ((1 << (HOST_BITS_PER_INT / 3 * 3)) - 1);
+      unsigned HOST_WIDE_INT beg = high >> excess;
+      unsigned HOST_WIDE_INT middle
+       = ((high & (((HOST_WIDE_INT) 1 << excess) - 1)) << (3 - excess)
+          | (low >> (HOST_BITS_PER_WIDE_INT / 3 * 3)));
+      unsigned HOST_WIDE_INT end
+       = low & (((unsigned HOST_WIDE_INT) 1
+                 << (HOST_BITS_PER_WIDE_INT / 3 * 3))
+                - 1);
+
       fprintf (asmfile, "%o%01o", beg, middle);
-      print_octal (end, HOST_BITS_PER_INT / 3);
+      print_octal (end, HOST_BITS_PER_WIDE_INT / 3);
     }
 }
 
 static void
 print_octal (value, digits)
-     unsigned int value;
+     unsigned HOST_WIDE_INT value;
      int digits;
 {
   int i;
@@ -1278,10 +1666,8 @@ dbxout_symbol (decl, local)
      tree decl;
      int local;
 {
-  int letter = 0;
   tree type = TREE_TYPE (decl);
   tree context = NULL_TREE;
-  int regno = -1;
 
   /* Cast avoids warning in old compilers.  */
   current_sym_code = (STAB_CODE_TYPE) 0;
@@ -1311,7 +1697,7 @@ dbxout_symbol (decl, local)
     case FUNCTION_DECL:
       if (DECL_RTL (decl) == 0)
        return;
-      if (TREE_EXTERNAL (decl))
+      if (DECL_EXTERNAL (decl))
        break;
       /* Don't mention a nested function under its parent.  */
       context = decl_function_context (decl);
@@ -1330,9 +1716,9 @@ dbxout_symbol (decl, local)
       current_sym_addr = XEXP (DECL_RTL (decl), 0);
 
       if (TREE_TYPE (type))
-       dbxout_type (TREE_TYPE (type), 0);
+       dbxout_type (TREE_TYPE (type), 0, 0);
       else
-       dbxout_type (void_type_node, 0);
+       dbxout_type (void_type_node, 0, 0);
 
       /* For a nested function, when that function is compiled,
         mention the containing function name
@@ -1354,63 +1740,138 @@ dbxout_symbol (decl, local)
 
       /* If this typedef name was defined by outputting the type,
         don't duplicate it.  */
-      if (typevec[TYPE_SYMTAB_ADDRESS (type)] == TYPE_DEFINED
+      if (typevec[TYPE_SYMTAB_ADDRESS (type)].status == TYPE_DEFINED
          && TYPE_NAME (TREE_TYPE (decl)) == decl)
        return;
 #endif
       /* Don't output the same typedef twice.
          And don't output what language-specific stuff doesn't want output.  */
-      if (TREE_ASM_WRITTEN (decl) || DECL_IGNORED_P (decl))
+      if (TREE_ASM_WRITTEN (decl) || TYPE_DECL_SUPPRESS_DEBUG (decl))
        return;
 
       FORCE_TEXT;
 
-      if (DECL_NAME (decl))
-       {
-         /* Output typedef name.  */
-         fprintf (asmfile, "%s \"%s:", ASM_STABS_OP,
-                  IDENTIFIER_POINTER (DECL_NAME (decl)));
-
-         /* If there is a typedecl for this type with the same name
-            as the tag, output an abbreviated form for that typedecl.  */
-         if (use_gdb_dbx_extensions && have_used_extensions
-             && (TREE_CODE (type) == RECORD_TYPE
-                 || TREE_CODE (type) == UNION_TYPE)
-             && (TYPE_NAME (type) == decl))
-           {
-             putc ('T', asmfile);
-             TREE_ASM_WRITTEN (TYPE_NAME (type)) = 1;
-           }
-         putc ('t', asmfile);
-         current_sym_code = DBX_DECL_STABS_CODE;
+      {
+       int tag_needed = 1;
+       int did_output = 0;
 
-         dbxout_type (type, 1);
-         dbxout_finish_symbol (decl);
-       }
-      else if (TYPE_NAME (type) != 0 && !TREE_ASM_WRITTEN (TYPE_NAME (type)))
-       {
-         /* Output a tag (a TYPE_DECL with no name, but the type has a name).
-            This is what represents `struct foo' with no typedef.  */
-         /* In C++, the name of a type is the corresponding typedef.
-            In C, it is an IDENTIFIER_NODE.  */
-         tree name = TYPE_NAME (type);
-         if (TREE_CODE (name) == TYPE_DECL)
-           name = DECL_NAME (name);
-
-         current_sym_code = DBX_DECL_STABS_CODE;
-         current_sym_value = 0;
-         current_sym_addr = 0;
-         current_sym_nchars = 2 + IDENTIFIER_LENGTH (name);
-
-         fprintf (asmfile, "%s \"%s:T", ASM_STABS_OP,
-                  IDENTIFIER_POINTER (name));
-         dbxout_type (type, 1);
-         dbxout_finish_symbol (0);
-       }
+       if (DECL_NAME (decl))
+         {
+           /* Nonzero means we must output a tag as well as a typedef.  */
+           tag_needed = 0;
+
+           /* Handle the case of a C++ structure or union
+              where the TYPE_NAME is a TYPE_DECL
+              which gives both a typedef name and a tag.  */
+           /* dbx requires the tag first and the typedef second.  */
+           if ((TREE_CODE (type) == RECORD_TYPE
+                || TREE_CODE (type) == UNION_TYPE
+                || TREE_CODE (type) == QUAL_UNION_TYPE)
+               && TYPE_NAME (type) == decl
+               && !(use_gnu_debug_info_extensions && have_used_extensions)
+               && !TREE_ASM_WRITTEN (TYPE_NAME (type))
+               /* Distinguish the implicit typedefs of C++
+                  from explicit ones that might be found in C.  */
+                && (!strcmp (lang_identify (), "cplusplus") 
+                   /* The following line maybe unnecessary;
+                      in 2.6, try removing it.  */
+                   || DECL_SOURCE_LINE (decl) == 0))
+             {
+               tree name = TYPE_NAME (type);
+               if (TREE_CODE (name) == TYPE_DECL)
+                 name = DECL_NAME (name);
+
+               current_sym_code = DBX_TYPE_DECL_STABS_CODE;
+               current_sym_value = 0;
+               current_sym_addr = 0;
+               current_sym_nchars = 2 + IDENTIFIER_LENGTH (name);
+
+               fprintf (asmfile, "%s \"%s:T", ASM_STABS_OP,
+                        IDENTIFIER_POINTER (name));
+               dbxout_type (type, 1, 0);
+               dbxout_finish_symbol (NULL_TREE);
+             }
 
-      /* Prevent duplicate output of a typedef.  */
-      TREE_ASM_WRITTEN (decl) = 1;
-      break;
+           /* Output typedef name.  */
+           fprintf (asmfile, "%s \"%s:", ASM_STABS_OP,
+                    IDENTIFIER_POINTER (DECL_NAME (decl)));
+
+           /* Short cut way to output a tag also.  */
+           if ((TREE_CODE (type) == RECORD_TYPE
+                || TREE_CODE (type) == UNION_TYPE
+                || TREE_CODE (type) == QUAL_UNION_TYPE)
+               && TYPE_NAME (type) == decl)
+             {
+               if (use_gnu_debug_info_extensions && have_used_extensions)
+                 {
+                   putc ('T', asmfile);
+                   TREE_ASM_WRITTEN (TYPE_NAME (type)) = 1;
+                 }
+#if 0 /* Now we generate the tag for this case up above.  */
+               else
+                 tag_needed = 1;
+#endif
+             }
+
+           putc ('t', asmfile);
+           current_sym_code = DBX_TYPE_DECL_STABS_CODE;
+
+           dbxout_type (type, 1, 0);
+           dbxout_finish_symbol (decl);
+           did_output = 1;
+         }
+
+       /* Don't output a tag if this is an incomplete type (TYPE_SIZE is
+          zero).  This prevents the sun4 Sun OS 4.x dbx from crashing.  */ 
+
+       if (tag_needed && TYPE_NAME (type) != 0
+           && (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE
+               || (DECL_NAME (TYPE_NAME (type)) != 0))
+           && TYPE_SIZE (type) != 0
+           && !TREE_ASM_WRITTEN (TYPE_NAME (type)))
+         {
+           /* For a TYPE_DECL with no name, but the type has a name,
+              output a tag.
+              This is what represents `struct foo' with no typedef.  */
+           /* In C++, the name of a type is the corresponding typedef.
+              In C, it is an IDENTIFIER_NODE.  */
+           tree name = TYPE_NAME (type);
+           if (TREE_CODE (name) == TYPE_DECL)
+             name = DECL_NAME (name);
+
+           current_sym_code = DBX_TYPE_DECL_STABS_CODE;
+           current_sym_value = 0;
+           current_sym_addr = 0;
+           current_sym_nchars = 2 + IDENTIFIER_LENGTH (name);
+
+           fprintf (asmfile, "%s \"%s:T", ASM_STABS_OP,
+                    IDENTIFIER_POINTER (name));
+           dbxout_type (type, 1, 0);
+           dbxout_finish_symbol (NULL_TREE);
+           did_output = 1;
+         }
+
+       /* If an enum type has no name, it cannot be referred to,
+          but we must output it anyway, since the enumeration constants
+          can be referred to.  */
+       if (!did_output && TREE_CODE (type) == ENUMERAL_TYPE)
+         {
+           current_sym_code = DBX_TYPE_DECL_STABS_CODE;
+           current_sym_value = 0;
+           current_sym_addr = 0;
+           current_sym_nchars = 2;
+
+           /* Some debuggers fail when given NULL names, so give this a
+              harmless name of ` '.  */
+           fprintf (asmfile, "%s \" :T", ASM_STABS_OP);
+           dbxout_type (type, 1, 0);
+           dbxout_finish_symbol (NULL_TREE);
+         }
+
+       /* Prevent duplicate output of a typedef.  */
+       TREE_ASM_WRITTEN (decl) = 1;
+       break;
+      }
 
     case PARM_DECL:
       /* Parm decls go in their own separate chains
@@ -1424,7 +1885,7 @@ dbxout_symbol (decl, local)
        return;
       /* Don't mention a variable that is external.
         Let the file that defines it describe it.  */
-      if (TREE_EXTERNAL (decl))
+      if (DECL_EXTERNAL (decl))
        break;
 
       /* If the variable is really a constant
@@ -1442,7 +1903,7 @@ dbxout_symbol (decl, local)
              if (TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE
                  || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
                {
-                 int ival = TREE_INT_CST_LOW (DECL_INITIAL (decl));
+                 HOST_WIDE_INT ival = TREE_INT_CST_LOW (DECL_INITIAL (decl));
 #ifdef DBX_OUTPUT_CONSTANT_SYMBOL
                  DBX_OUTPUT_CONSTANT_SYMBOL (asmfile, name, ival);
 #else
@@ -1460,217 +1921,248 @@ dbxout_symbol (decl, local)
          /* else it is something we handle like a normal variable.  */
        }
 
-      DECL_RTL (decl) = eliminate_regs (DECL_RTL (decl));
+      DECL_RTL (decl) = eliminate_regs (DECL_RTL (decl), 0, NULL_RTX);
 #ifdef LEAF_REG_REMAP
       if (leaf_function)
        leaf_renumber_regs_insn (DECL_RTL (decl));
 #endif
 
-      /* Don't mention a variable at all
-        if it was completely optimized into nothingness.
+      dbxout_symbol_location (decl, type, 0, DECL_RTL (decl));
+    }
+}
+\f
+/* Output the stab for DECL, a VAR_DECL, RESULT_DECL or PARM_DECL.
+   Add SUFFIX to its name, if SUFFIX is not 0.
+   Describe the variable as residing in HOME
+   (usually HOME is DECL_RTL (DECL), but not always).  */
 
-        If DECL was from an inline function, then it's rtl
-        is not identically the rtl that was used in this
-        particular compilation.  */
-      if (GET_CODE (DECL_RTL (decl)) == REG)
+static void
+dbxout_symbol_location (decl, type, suffix, home)
+     tree decl, type;
+     char *suffix;
+     rtx home;
+{
+  int letter = 0;
+  int regno = -1;
+
+  /* Don't mention a variable at all
+     if it was completely optimized into nothingness.
+     
+     If the decl was from an inline function, then it's rtl
+     is not identically the rtl that was used in this
+     particular compilation.  */
+  if (GET_CODE (home) == REG)
+    {
+      regno = REGNO (home);
+      if (regno >= FIRST_PSEUDO_REGISTER)
+       return;
+    }
+  else if (GET_CODE (home) == SUBREG)
+    {
+      rtx value = home;
+      int offset = 0;
+      while (GET_CODE (value) == SUBREG)
        {
-         regno = REGNO (DECL_RTL (decl));
-         if (regno >= FIRST_PSEUDO_REGISTER)
-           regno = reg_renumber[REGNO (DECL_RTL (decl))];
-         if (regno < 0)
-           break;
+         offset += SUBREG_WORD (value);
+         value = SUBREG_REG (value);
        }
-      else if (GET_CODE (DECL_RTL (decl)) == SUBREG)
+      if (GET_CODE (value) == REG)
        {
-         rtx value = DECL_RTL (decl);
-         int offset = 0;
-         while (GET_CODE (value) == SUBREG)
-           {
-             offset += SUBREG_WORD (value);
-             value = SUBREG_REG (value);
-           }
-         if (GET_CODE (value) == REG)
-           {
-             regno = REGNO (value);
-             if (regno >= FIRST_PSEUDO_REGISTER)
-               regno = reg_renumber[REGNO (value)];
-             if (regno >= 0)
-               regno += offset;
-           }
+         regno = REGNO (value);
+         if (regno >= FIRST_PSEUDO_REGISTER)
+           return;
+         regno += offset;
        }
+      alter_subreg (home);
+    }
 
-      /* The kind-of-variable letter depends on where
-        the variable is and on the scope of its name:
-        G and N_GSYM for static storage and global scope,
-        S for static storage and file scope,
-        V for static storage and local scope,
-           for those two, use N_LCSYM if data is in bss segment,
-           N_STSYM if in data segment, N_FUN otherwise.
-           (We used N_FUN originally, then changed to N_STSYM
-           to please GDB.  However, it seems that confused ld.
-           Now GDB has been fixed to like N_FUN, says Kingdon.)
-        no letter at all, and N_LSYM, for auto variable,
-        r and N_RSYM for register variable.  */
-
-      if (GET_CODE (DECL_RTL (decl)) == MEM
-         && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF)
+  /* The kind-of-variable letter depends on where
+     the variable is and on the scope of its name:
+     G and N_GSYM for static storage and global scope,
+     S for static storage and file scope,
+     V for static storage and local scope,
+     for those two, use N_LCSYM if data is in bss segment,
+     N_STSYM if in data segment, N_FUN otherwise.
+     (We used N_FUN originally, then changed to N_STSYM
+     to please GDB.  However, it seems that confused ld.
+     Now GDB has been fixed to like N_FUN, says Kingdon.)
+     no letter at all, and N_LSYM, for auto variable,
+     r and N_RSYM for register variable.  */
+
+  if (GET_CODE (home) == MEM
+      && GET_CODE (XEXP (home, 0)) == SYMBOL_REF)
+    {
+      if (TREE_PUBLIC (decl))
        {
-         if (TREE_PUBLIC (decl))
-           {
-             letter = 'G';
-             current_sym_code = N_GSYM;
-           }
+         letter = 'G';
+         current_sym_code = N_GSYM;
+       }
+      else
+       {
+         current_sym_addr = XEXP (home, 0);
+
+         letter = decl_function_context (decl) ? 'V' : 'S';
+
+         /* This should be the same condition as in assemble_variable, but
+            we don't have access to dont_output_data here.  So, instead,
+            we rely on the fact that error_mark_node initializers always
+            end up in bss for C++ and never end up in bss for C.  */
+         if (DECL_INITIAL (decl) == 0
+             || (!strcmp (lang_identify (), "cplusplus")
+                 && DECL_INITIAL (decl) == error_mark_node))
+           current_sym_code = N_LCSYM;
+         else if (DECL_IN_TEXT_SECTION (decl))
+           /* This is not quite right, but it's the closest
+              of all the codes that Unix defines.  */
+           current_sym_code = DBX_STATIC_CONST_VAR_CODE;
          else
            {
-             current_sym_addr = XEXP (DECL_RTL (decl), 0);
-
-             letter = TREE_PERMANENT (decl) ? 'S' : 'V';
-
-             if (!DECL_INITIAL (decl))
-               current_sym_code = N_LCSYM;
-             else if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl))
-               /* This is not quite right, but it's the closest
-                  of all the codes that Unix defines.  */
-               current_sym_code = DBX_STATIC_CONST_VAR_CODE;
-             else
-               {
-/* Ultrix `as' seems to need this.  */
+             /* Ultrix `as' seems to need this.  */
 #ifdef DBX_STATIC_STAB_DATA_SECTION
-                 data_section ();
+             data_section ();
 #endif
-                 current_sym_code = N_STSYM;
-               }
+             current_sym_code = N_STSYM;
            }
        }
-      else if (regno >= 0)
-       {
-         letter = 'r';
-         current_sym_code = N_RSYM;
-         current_sym_value = DBX_REGISTER_NUMBER (regno);
-       }
-      else if (GET_CODE (DECL_RTL (decl)) == SUBREG)
+    }
+  else if (regno >= 0)
+    {
+      letter = 'r';
+      current_sym_code = N_RSYM;
+      current_sym_value = DBX_REGISTER_NUMBER (regno);
+    }
+  else if (GET_CODE (home) == MEM
+          && (GET_CODE (XEXP (home, 0)) == MEM
+              || (GET_CODE (XEXP (home, 0)) == REG
+                  && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM)))
+    /* If the value is indirect by memory or by a register
+       that isn't the frame pointer
+       then it means the object is variable-sized and address through
+       that register or stack slot.  DBX has no way to represent this
+       so all we can do is output the variable as a pointer.
+       If it's not a parameter, ignore it.
+       (VAR_DECLs like this can be made by integrate.c.)  */
+    {
+      if (GET_CODE (XEXP (home, 0)) == REG)
        {
-         rtx value = DECL_RTL (decl);
-         int offset = 0;
-         while (GET_CODE (value) == SUBREG)
-           {
-             offset += SUBREG_WORD (value);
-             value = SUBREG_REG (value);
-           }
          letter = 'r';
          current_sym_code = N_RSYM;
-         current_sym_value = DBX_REGISTER_NUMBER (REGNO (value) + offset);
-       }
-      else if (GET_CODE (DECL_RTL (decl)) == MEM
-              && (GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
-                  || (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG
-                      && REGNO (XEXP (DECL_RTL (decl), 0)) != FRAME_POINTER_REGNUM)))
-       /* If the value is indirect by memory or by a register
-          that isn't the frame pointer
-          then it means the object is variable-sized and address through
-          that register or stack slot.  DBX has no way to represent this
-          so all we can do is output the variable as a pointer.
-          If it's not a parameter, ignore it.
-          (VAR_DECLs like this can be made by integrate.c.)  */
-       {
-         if (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG)
-           {
-             letter = 'r';
-             current_sym_code = N_RSYM;
-             current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (DECL_RTL (decl), 0)));
-           }
-         else
-           {
-             current_sym_code = N_LSYM;
-             /* DECL_RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))).
-                We want the value of that CONST_INT.  */
-             current_sym_value
-               = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (DECL_RTL (decl), 0), 0));
-           }
-
-         /* Effectively do build_pointer_type, but don't cache this type,
-            since it might be temporary whereas the type it points to
-            might have been saved for inlining.  */
-         type = make_node (REFERENCE_TYPE);
-         TREE_TYPE (type) = TREE_TYPE (decl);
+         current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (home, 0)));
        }
-      else if (GET_CODE (DECL_RTL (decl)) == MEM
-              && GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG)
-       {
-         current_sym_code = N_LSYM;
-         current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (decl), 0));
-       }
-      else if (GET_CODE (DECL_RTL (decl)) == MEM
-              && GET_CODE (XEXP (DECL_RTL (decl), 0)) == PLUS
-              && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 1)) == CONST_INT)
+      else
        {
          current_sym_code = N_LSYM;
-         /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...)))
+         /* RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))).
             We want the value of that CONST_INT.  */
-         current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (decl), 0));
-       }
-      else if (GET_CODE (DECL_RTL (decl)) == MEM
-              && GET_CODE (XEXP (DECL_RTL (decl), 0)) == CONST)
-       {
-         /* Handle an obscure case which can arise when optimizing and
-            when there are few available registers.  (This is *always*
-            the case for i386/i486 targets).  The DECL_RTL looks like
-            (MEM (CONST ...)) even though this variable is a local `auto'
-            or a local `register' variable.  In effect, what has happened
-            is that the reload pass has seen that all assignments and
-            references for one such a local variable can be replaced by
-            equivalent assignments and references to some static storage
-            variable, thereby avoiding the need for a register.  In such
-            cases we're forced to lie to debuggers and tell them that
-            this variable was itself `static'.  */
-         current_sym_code = N_LCSYM;
-         letter = 'V';
-         current_sym_addr = XEXP (XEXP (DECL_RTL (decl), 0), 0);
+         current_sym_value
+           = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (home, 0), 0));
        }
+
+      /* Effectively do build_pointer_type, but don't cache this type,
+        since it might be temporary whereas the type it points to
+        might have been saved for inlining.  */
+      /* Don't use REFERENCE_TYPE because dbx can't handle that.  */
+      type = make_node (POINTER_TYPE);
+      TREE_TYPE (type) = TREE_TYPE (decl);
+    }
+  else if (GET_CODE (home) == MEM
+          && GET_CODE (XEXP (home, 0)) == REG)
+    {
+      current_sym_code = N_LSYM;
+      current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0));
+    }
+  else if (GET_CODE (home) == MEM
+          && GET_CODE (XEXP (home, 0)) == PLUS
+          && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT)
+    {
+      current_sym_code = N_LSYM;
+      /* RTL looks like (MEM (PLUS (REG...) (CONST_INT...)))
+        We want the value of that CONST_INT.  */
+      current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0));
+    }
+  else if (GET_CODE (home) == MEM
+          && GET_CODE (XEXP (home, 0)) == CONST)
+    {
+      /* Handle an obscure case which can arise when optimizing and
+        when there are few available registers.  (This is *always*
+        the case for i386/i486 targets).  The RTL looks like
+        (MEM (CONST ...)) even though this variable is a local `auto'
+        or a local `register' variable.  In effect, what has happened
+        is that the reload pass has seen that all assignments and
+        references for one such a local variable can be replaced by
+        equivalent assignments and references to some static storage
+        variable, thereby avoiding the need for a register.  In such
+        cases we're forced to lie to debuggers and tell them that
+        this variable was itself `static'.  */
+      current_sym_code = N_LCSYM;
+      letter = 'V';
+      current_sym_addr = XEXP (XEXP (home, 0), 0);
+    }
+  else if (GET_CODE (home) == CONCAT)
+    {
+      tree subtype = TREE_TYPE (type);
+
+      /* If the variable's storage is in two parts,
+        output each as a separate stab with a modified name.  */
+      if (WORDS_BIG_ENDIAN)
+       dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 0));
       else
-       /* Address might be a MEM, when DECL is a variable-sized object.
-          Or it might be const0_rtx, meaning previous passes
-          want us to ignore this variable.  */
-       break;
+       dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 0));
 
-      /* Ok, start a symtab entry and output the variable name.  */
-      FORCE_TEXT;
+      /* Cast avoids warning in old compilers.  */
+      current_sym_code = (STAB_CODE_TYPE) 0;
+      current_sym_value = 0;
+      current_sym_addr = 0;
+      dbxout_prepare_symbol (decl);
 
-#ifdef DBX_STATIC_BLOCK_START
-      DBX_STATIC_BLOCK_START (asmfile, current_sym_code);
-#endif
+      if (WORDS_BIG_ENDIAN)
+       dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 1));
+      else
+       dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 1));
+      return;
+    }
+  else
+    /* Address might be a MEM, when DECL is a variable-sized object.
+       Or it might be const0_rtx, meaning previous passes
+       want us to ignore this variable.  */
+    return;
 
-      /* One slight hitch: if this is a VAR_DECL which is a static
-        class member, we must put out the mangled name instead of the
-        DECL_NAME.  */
-      {
-       char *name;
-       /* Note also that static member (variable) names DO NOT begin
-          with underscores in .stabs directives.  */
-       if (DECL_LANG_SPECIFIC (decl))
-         {
-           name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  /* Ok, start a symtab entry and output the variable name.  */
+  FORCE_TEXT;
 
-#if 0 /* Tiemann says get rid of this.  */
-           /* Adding 1 here only works on systems
-              which flush an initial underscore.  */
-           if (name[0] == '_')
-             name += 1;
+#ifdef DBX_STATIC_BLOCK_START
+  DBX_STATIC_BLOCK_START (asmfile, current_sym_code);
 #endif
-         }
-       else
-         name = IDENTIFIER_POINTER (DECL_NAME (decl));
-       fprintf (asmfile, "%s \"%s:", ASM_STABS_OP, name);
-      }
-      if (letter) putc (letter, asmfile);
-      dbxout_type (type, 0);
-      dbxout_finish_symbol (decl);
+
+  dbxout_symbol_name (decl, suffix, letter);
+  dbxout_type (type, 0, 0);
+  dbxout_finish_symbol (decl);
 
 #ifdef DBX_STATIC_BLOCK_END
-      DBX_STATIC_BLOCK_END (asmfile, current_sym_code);
+  DBX_STATIC_BLOCK_END (asmfile, current_sym_code);
 #endif
-      break;
-    }
+}
+\f
+/* Output the symbol name of DECL for a stabs, with suffix SUFFIX.
+   Then output LETTER to indicate the kind of location the symbol has.  */
+
+static void
+dbxout_symbol_name (decl, suffix, letter)
+     tree decl;
+     char *suffix;
+     int letter;
+{
+  /* One slight hitch: if this is a VAR_DECL which is a static
+     class member, we must put out the mangled name instead of the
+     DECL_NAME.  Note also that static member (variable) names DO NOT begin
+     with underscores in .stabs directives.  */
+  char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  if (name == 0)
+    name = "(anon)";
+  fprintf (asmfile, "%s \"%s%s:", ASM_STABS_OP, name,
+          (suffix ? suffix : ""));
+
+  if (letter) putc (letter, asmfile);
 }
 
 static void
@@ -1692,10 +2184,8 @@ dbxout_finish_symbol (sym)
   DBX_FINISH_SYMBOL (sym);
 #else
   int line = 0;
-#ifdef WINNING_GDB
-  if (sym != 0)
+  if (use_gnu_debug_info_extensions && sym != 0)
     line = DECL_SOURCE_LINE (sym);
-#endif
 
   fprintf (asmfile, "\",%d,0,%d,", current_sym_code, line);
   if (current_sym_addr)
@@ -1743,8 +2233,8 @@ dbxout_parms (parms)
        /* Perform any necessary register eliminations on the parameter's rtl,
           so that the debugging output will be accurate.  */
        DECL_INCOMING_RTL (parms)
-         = eliminate_regs (DECL_INCOMING_RTL (parms), 0, 0);
-       DECL_RTL (parms) = eliminate_regs (DECL_RTL (parms), 0, 0);
+         = eliminate_regs (DECL_INCOMING_RTL (parms), 0, NULL_RTX);
+       DECL_RTL (parms) = eliminate_regs (DECL_RTL (parms), 0, NULL_RTX);
 #ifdef LEAF_REG_REMAP
        if (leaf_function)
          {
@@ -1775,46 +2265,18 @@ dbxout_parms (parms)
              {
                current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms));
 
-               fprintf (asmfile, "%s \"%s:p", ASM_STABS_OP,
-                        IDENTIFIER_POINTER (DECL_NAME (parms)));
+               fprintf (asmfile, "%s \"%s:%c", ASM_STABS_OP,
+                        IDENTIFIER_POINTER (DECL_NAME (parms)),
+                        DBX_MEMPARM_STABS_LETTER);
              }
            else
              {
                current_sym_nchars = 8;
-               fprintf (asmfile, "%s \"(anon):p", ASM_STABS_OP);
+               fprintf (asmfile, "%s \"(anon):%c", ASM_STABS_OP,
+                        DBX_MEMPARM_STABS_LETTER);
              }
 
-           if (GET_CODE (DECL_RTL (parms)) == REG
-               && REGNO (DECL_RTL (parms)) >= 0
-               && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER)
-             dbxout_type (DECL_ARG_TYPE (parms), 0);
-           else
-             {
-               int original_value = current_sym_value;
-
-               /* This is the case where the parm is passed as an int or double
-                  and it is converted to a char, short or float and stored back
-                  in the parmlist.  In this case, describe the parm
-                  with the variable's declared type, and adjust the address
-                  if the least significant bytes (which we are using) are not
-                  the first ones.  */
-#if BYTES_BIG_ENDIAN
-               if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms))
-                 current_sym_value += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms)))
-                                       - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));
-#endif
-
-               if (GET_CODE (DECL_RTL (parms)) == MEM
-                   && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS
-                   && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT
-                   && INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == current_sym_value)
-                 dbxout_type (TREE_TYPE (parms), 0);
-               else
-                 {
-                   current_sym_value = original_value;
-                   dbxout_type (DECL_ARG_TYPE (parms), 0);
-                 }
-             }
+           dbxout_type (DECL_ARG_TYPE (parms), 0, 0);
            current_sym_value = DEBUGGER_ARG_OFFSET (current_sym_value, addr);
            dbxout_finish_symbol (parms);
          }
@@ -1822,6 +2284,7 @@ dbxout_parms (parms)
          {
            rtx best_rtl;
            char regparm_letter;
+           tree parm_type;
            /* Parm passed in registers and lives in registers or nowhere.  */
 
            current_sym_code = DBX_REGPARM_STABS_CODE;
@@ -1831,14 +2294,23 @@ dbxout_parms (parms)
            /* If parm lives in a register, use that register;
               pretend the parm was passed there.  It would be more consistent
               to describe the register where the parm was passed,
-              but in practice that register usually holds something else.  */
+              but in practice that register usually holds something else.
+
+              If we use DECL_RTL, then we must use the declared type of
+              the variable, not the type that it arrived in.  */
            if (REGNO (DECL_RTL (parms)) >= 0
                && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER)
-             best_rtl = DECL_RTL (parms);
-           /* If the parm lives nowhere,
-              use the register where it was passed.  */
+             {
+               best_rtl = DECL_RTL (parms);
+               parm_type = TREE_TYPE (parms);
+             }
+           /* If the parm lives nowhere, use the register where it was
+              passed.  It is also better to use the declared type here.  */
            else
-             best_rtl = DECL_INCOMING_RTL (parms);
+             {
+               best_rtl = DECL_INCOMING_RTL (parms);
+               parm_type = TREE_TYPE (parms);
+             }
            current_sym_value = DBX_REGISTER_NUMBER (REGNO (best_rtl));
 
            FORCE_TEXT;
@@ -1856,11 +2328,69 @@ dbxout_parms (parms)
                         regparm_letter);
              }
 
-           dbxout_type (DECL_ARG_TYPE (parms), 0);
+           dbxout_type (parm_type, 0, 0);
+           dbxout_finish_symbol (parms);
+         }
+       else if (GET_CODE (DECL_RTL (parms)) == MEM
+                && GET_CODE (XEXP (DECL_RTL (parms), 0)) == REG
+                && REGNO (XEXP (DECL_RTL (parms), 0)) != HARD_FRAME_POINTER_REGNUM
+                && REGNO (XEXP (DECL_RTL (parms), 0)) != STACK_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+                && REGNO (XEXP (DECL_RTL (parms), 0)) != ARG_POINTER_REGNUM
+#endif
+                )
+         {
+           /* Parm was passed via invisible reference.
+              That is, its address was passed in a register.
+              Output it as if it lived in that register.
+              The debugger will know from the type
+              that it was actually passed by invisible reference.  */
+
+           char regparm_letter;
+           /* Parm passed in registers and lives in registers or nowhere.  */
+
+           current_sym_code = DBX_REGPARM_STABS_CODE;
+           if (use_gnu_debug_info_extensions)
+             regparm_letter = GDB_INV_REF_REGPARM_STABS_LETTER;
+           else
+             regparm_letter = DBX_REGPARM_STABS_LETTER;
+
+           /* DECL_RTL looks like (MEM (REG...).  Get the register number.
+              If it is an unallocated pseudo-reg, then use the register where
+              it was passed instead.  */
+           if (REGNO (XEXP (DECL_RTL (parms), 0)) >= 0
+               && REGNO (XEXP (DECL_RTL (parms), 0)) < FIRST_PSEUDO_REGISTER)
+             current_sym_value = REGNO (XEXP (DECL_RTL (parms), 0));
+           else
+             current_sym_value = REGNO (DECL_INCOMING_RTL (parms));
+
+           current_sym_addr = 0;
+
+           FORCE_TEXT;
+           if (DECL_NAME (parms))
+             {
+               current_sym_nchars = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms)));
+
+               fprintf (asmfile, "%s \"%s:%c", ASM_STABS_OP,
+                        IDENTIFIER_POINTER (DECL_NAME (parms)),
+                        regparm_letter);
+             }
+           else
+             {
+               current_sym_nchars = 8;
+               fprintf (asmfile, "%s \"(anon):%c", ASM_STABS_OP,
+                        regparm_letter);
+             }
+
+           dbxout_type (TREE_TYPE (parms), 0, 0);
            dbxout_finish_symbol (parms);
          }
        else if (GET_CODE (DECL_RTL (parms)) == MEM
-                && XEXP (DECL_RTL (parms), 0) != const0_rtx)
+                && XEXP (DECL_RTL (parms), 0) != const0_rtx
+                /* ??? A constant address for a parm can happen
+                   when the reg it lives in is equiv to a constant in memory.
+                   Should make this not happen, after 2.4.  */
+                && ! CONSTANT_P (XEXP (DECL_RTL (parms), 0)))
          {
            /* Parm was passed in registers but lives on the stack.  */
 
@@ -1881,19 +2411,21 @@ dbxout_parms (parms)
              {
                current_sym_nchars = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms)));
 
-               fprintf (asmfile, "%s \"%s:p", ASM_STABS_OP,
-                        IDENTIFIER_POINTER (DECL_NAME (parms)));
+               fprintf (asmfile, "%s \"%s:%c", ASM_STABS_OP,
+                        IDENTIFIER_POINTER (DECL_NAME (parms)),
+                        DBX_MEMPARM_STABS_LETTER);
              }
            else
              {
                current_sym_nchars = 8;
-               fprintf (asmfile, "%s \"(anon):p", ASM_STABS_OP);
+               fprintf (asmfile, "%s \"(anon):%c", ASM_STABS_OP,
+               DBX_MEMPARM_STABS_LETTER);
              }
 
            current_sym_value
              = DEBUGGER_ARG_OFFSET (current_sym_value,
                                     XEXP (DECL_RTL (parms), 0));
-           dbxout_type (TREE_TYPE (parms), 0);
+           dbxout_type (TREE_TYPE (parms), 0, 0);
            dbxout_finish_symbol (parms);
          }
       }
@@ -1915,7 +2447,7 @@ dbxout_reg_parms (parms)
      tree parms;
 {
   for (; parms; parms = TREE_CHAIN (parms))
-    if (DECL_NAME (parms))
+    if (DECL_NAME (parms) && PARM_PASSED_IN_MEMORY (parms))
       {
        dbxout_prepare_symbol (parms);
 
@@ -1923,65 +2455,17 @@ dbxout_reg_parms (parms)
           but were passed in memory.  */
        if (GET_CODE (DECL_RTL (parms)) == REG
            && REGNO (DECL_RTL (parms)) >= 0
-           && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER
-           && PARM_PASSED_IN_MEMORY (parms))
-         {
-           current_sym_code = N_RSYM;
-           current_sym_value = DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms)));
-           current_sym_addr = 0;
-
-           FORCE_TEXT;
-           if (DECL_NAME (parms))
-             {
-               current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms));
-               fprintf (asmfile, "%s \"%s:r", ASM_STABS_OP,
-                        IDENTIFIER_POINTER (DECL_NAME (parms)));
-             }
-           else
-             {
-               current_sym_nchars = 8;
-               fprintf (asmfile, "%s \"(anon):r", ASM_STABS_OP);
-             }
-           dbxout_type (TREE_TYPE (parms), 0);
-           dbxout_finish_symbol (parms);
-         }
+           && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER)
+         dbxout_symbol_location (parms, TREE_TYPE (parms),
+                                 0, DECL_RTL (parms));
+       else if (GET_CODE (DECL_RTL (parms)) == CONCAT)
+         dbxout_symbol_location (parms, TREE_TYPE (parms),
+                                 0, DECL_RTL (parms));
        /* Report parms that live in memory but not where they were passed.  */
        else if (GET_CODE (DECL_RTL (parms)) == MEM
-                && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS
-                && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT
-                && PARM_PASSED_IN_MEMORY (parms)
                 && ! rtx_equal_p (DECL_RTL (parms), DECL_INCOMING_RTL (parms)))
-         {
-#if 0 /* ??? It is not clear yet what should replace this.  */
-           int offset = DECL_OFFSET (parms) / BITS_PER_UNIT;
-           /* A parm declared char is really passed as an int,
-              so it occupies the least significant bytes.
-              On a big-endian machine those are not the low-numbered ones.  */
-#if BYTES_BIG_ENDIAN
-           if (offset != -1 && TREE_TYPE (parms) != DECL_ARG_TYPE (parms))
-             offset += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms)))
-                        - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));
-#endif
-           if (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) != offset) {...}
-#endif
-           current_sym_code = N_LSYM;
-           current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (parms), 0));
-           current_sym_addr = 0;
-           FORCE_TEXT;
-           if (DECL_NAME (parms))
-             {
-               current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms));
-               fprintf (asmfile, "%s \"%s:", ASM_STABS_OP,
-                        IDENTIFIER_POINTER (DECL_NAME (parms)));
-             }
-           else
-             {
-               current_sym_nchars = 8;
-               fprintf (asmfile, "%s \"(anon):", ASM_STABS_OP);
-             }
-           dbxout_type (TREE_TYPE (parms), 0);
-           dbxout_finish_symbol (parms);
-         }
+         dbxout_symbol_location (parms, TREE_TYPE (parms),
+                                 0, DECL_RTL (parms));
       }
 }
 \f
@@ -1995,7 +2479,7 @@ dbxout_args (args)
   while (args)
     {
       putc (',', asmfile);
-      dbxout_type (TREE_VALUE (args), 0);
+      dbxout_type (TREE_VALUE (args), 0, 0);
       CHARS (1);
       args = TREE_CHAIN (args);
     }
@@ -2085,9 +2569,17 @@ dbxout_block (block, depth, args)
                    }
                }
 
+#ifdef DBX_OUTPUT_LBRAC
+             DBX_OUTPUT_LBRAC (asmfile, buf);
+#else
              fprintf (asmfile, "%s %d,0,0,", ASM_STABN_OP, N_LBRAC);
              assemble_name (asmfile, buf);
+#if DBX_BLOCKS_FUNCTION_RELATIVE
+             fputc ('-', asmfile);
+             assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+#endif
              fprintf (asmfile, "\n");
+#endif
            }
          else if (depth > 0)
            /* Count blocks the same way regardless of debug_info_level.  */
@@ -2103,16 +2595,24 @@ dbxout_block (block, depth, args)
 #endif
 
          /* Output the subblocks.  */
-         dbxout_block (BLOCK_SUBBLOCKS (block), depth + 1, 0);
+         dbxout_block (BLOCK_SUBBLOCKS (block), depth + 1, NULL_TREE);
 
          /* Refer to the marker for the end of the block.  */
          if (depth > 0 && debug_info_level != DINFO_LEVEL_TERSE)
            {
              char buf[20];
              ASM_GENERATE_INTERNAL_LABEL (buf, "LBE", blocknum);
+#ifdef DBX_OUTPUT_RBRAC
+             DBX_OUTPUT_RBRAC (asmfile, buf);
+#else
              fprintf (asmfile, "%s %d,0,0,", ASM_STABN_OP, N_RBRAC);
              assemble_name (asmfile, buf);
+#if DBX_BLOCKS_FUNCTION_RELATIVE
+             fputc ('-', asmfile);
+             assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+#endif
              fprintf (asmfile, "\n");
+#endif
            }
        }
       block = BLOCK_CHAIN (block);