OSDN Git Service

* pa.h (OVERRIDE_OPTIONS): Define. Give a warning if -fpic or
[pf3gnuchains/gcc-fork.git] / gcc / dwarfout.c
index a6d80f0..49339ae 100644 (file)
@@ -2,7 +2,7 @@
    Network Computing Devices, August, September, October, November 1990.
 
    Output Dwarf format symbol table information from the GNU C compiler.
-   Copyright (C) 1992 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -28,6 +28,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tree.h"
 #include "flags.h"
 #include "rtl.h"
+#include "hard-reg-set.h"
 #include "insn-config.h"
 #include "reload.h"
 #include "output.h"
@@ -38,7 +39,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #endif
 
 /* #define NDEBUG 1 */
-#include <assert.h>
+#include "assert.h"
 
 #if defined(DWARF_TIMESTAMPS)
 #if defined(POSIX)
@@ -80,6 +81,12 @@ extern char *rindex ();
 #define ASM_COMMENT_START ";#"
 #endif
 
+/* How to print out a register name.  */
+#ifndef PRINT_REG
+#define PRINT_REG(RTX, CODE, FILE) \
+  fprintf ((FILE), "%s", reg_names[REGNO (RTX)])
+#endif
+
 /* Define a macro which returns non-zero for any tagged type which is
    used (directly or indirectly) in the specification of either some
    function's return type or some formal parameter of some function.
@@ -277,6 +284,13 @@ static tree fake_containing_scope;
 
 static unsigned current_funcdef_number = 1;
 
+/* A pointer to the ..._DECL node which we have most recently been working
+   on.  We keep this around just in case something about it looks screwy
+   and we want to tell the user what the source coordinates for the actual
+   declaration are.  */
+
+static tree dwarf_last_decl;
+
 /* Forward declarations for functions defined in this file.  */
 
 static void output_type ();
@@ -518,6 +532,12 @@ static unsigned lookup_filename ();
 #ifndef SL_END_LABEL_FMT
 #define SL_END_LABEL_FMT       ".L_sl%u_e"
 #endif
+#ifndef BODY_BEGIN_LABEL_FMT
+#define BODY_BEGIN_LABEL_FMT   ".L_b%u"
+#endif
+#ifndef BODY_END_LABEL_FMT
+#define BODY_END_LABEL_FMT     ".L_b%u_e"
+#endif
 #ifndef FUNC_END_LABEL_FMT
 #define FUNC_END_LABEL_FMT     ".L_f%u_e"
 #endif
@@ -742,6 +762,38 @@ is_pseudo_reg (rtl)
              && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
 }
 
+inline tree
+type_main_variant (type)
+     register tree type;
+{
+  type = TYPE_MAIN_VARIANT (type);
+
+  /* There really should be only one main variant among any group of variants
+     of a given type (and all of the MAIN_VARIANT values for all members of
+     the group should point to that one type) but sometimes the C front-end
+     messes this up for array types, so we work around that bug here.  */
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      while (type != TYPE_MAIN_VARIANT (type))
+        type = TYPE_MAIN_VARIANT (type);
+    }
+
+  return type;
+}
+
+/* Return non-zero if the given type node represents a tagged type.  */
+
+inline int
+is_tagged_type (type)
+     register tree type;
+{
+  register enum tree_code code = TREE_CODE (type);
+
+  return (code == RECORD_TYPE || code == UNION_TYPE
+         || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
+}
+
 static char *
 dwarf_tag_name (tag)
      register unsigned tag;
@@ -863,6 +915,8 @@ dwarf_attr_name (attr)
     case AT_src_info:                  return "AT_src_info";
     case AT_mac_info:                  return "AT_mac_info";
     case AT_src_coords:                        return "AT_src_coords";
+    case AT_body_begin:                        return "AT_body_begin";
+    case AT_body_end:                  return "AT_body_end";
 
     default:                           return "AT_<unknown>";
     }
@@ -1091,23 +1145,34 @@ output_signed_leb128 (value)
 /**************** utility functions for attribute functions ******************/
 
 /* Given a pointer to a BLOCK node return non-zero if (and only if) the
-   node in question represents the outermost block (i.e. the "body block")
-   of a function or method.
-
-   For any BLOCK node representing a "body block", the BLOCK_SUPERCONTEXT
-   of the node will point to another BLOCK node which represents the outer-
-   most (function) scope for the function or method.  The BLOCK_SUPERCONTEXT
-   of that node in turn will point to the relevant FUNCTION_DECL node.
+   node in question represents the outermost pair of curly braces (i.e.
+   the "body block") of a function or method.
+
+   For any BLOCK node representing a "body block" of a function or method,
+   the BLOCK_SUPERCONTEXT of the node will point to another BLOCK node
+   which represents the outermost (function) scope for the function or
+   method (i.e. the one which includes the formal parameters).  The
+   BLOCK_SUPERCONTEXT of *that* node in turn will point to the relevant
+   FUNCTION_DECL node.
 */
 
 inline int
 is_body_block (stmt)
      register tree stmt;
 {
-  register enum tree_code code
-    = TREE_CODE (BLOCK_SUPERCONTEXT (BLOCK_SUPERCONTEXT (stmt)));
+  if (TREE_CODE (stmt) == BLOCK)
+    {
+      register tree parent = BLOCK_SUPERCONTEXT (stmt);
 
-  return (code == FUNCTION_DECL);
+      if (TREE_CODE (parent) == BLOCK)
+       {
+         register tree grandparent = BLOCK_SUPERCONTEXT (parent);
+
+         if (TREE_CODE (grandparent) == FUNCTION_DECL)
+           return 1;
+       }
+    }
+  return 0;
 }
 
 /* Given a pointer to a tree node for some type, return a Dwarf fundamental
@@ -1272,10 +1337,10 @@ root_type (type)
 
       case POINTER_TYPE:
       case REFERENCE_TYPE:
-       return TYPE_MAIN_VARIANT (root_type (TREE_TYPE (type)));
+       return type_main_variant (root_type (TREE_TYPE (type)));
 
       default:
-       return TYPE_MAIN_VARIANT (type);
+       return type_main_variant (type);
     }
 }
 
@@ -1335,6 +1400,7 @@ type_is_fundamental (type)
       case ARRAY_TYPE:
       case RECORD_TYPE:
       case UNION_TYPE:
+      case QUAL_UNION_TYPE:
       case ENUMERAL_TYPE:
       case FUNCTION_TYPE:
       case METHOD_TYPE:
@@ -1409,13 +1475,35 @@ equate_type_number_to_die_number (type)
      to get the equate to come out right, we need to get the main variant
      itself here.  */
 
-  type = TYPE_MAIN_VARIANT (type);
+  type = type_main_variant (type);
 
   sprintf (type_label, TYPE_NAME_FMT, TYPE_UID (type));
   sprintf (die_label, DIE_BEGIN_LABEL_FMT, current_dienum);
   ASM_OUTPUT_DEF (asm_out_file, type_label, die_label);
 }
 
+static void
+output_reg_number (rtl)
+     register rtx rtl;
+{
+  register unsigned regno = REGNO (rtl);
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      warning_with_decl (dwarf_last_decl, "internal regno botch: regno = %d\n",
+                        regno);
+      regno = 0;
+    }
+  fprintf (asm_out_file, "\t%s\t0x%x",
+          UNALIGNED_INT_ASM_OP, DBX_REGISTER_NUMBER (regno));
+  if (flag_verbose_asm)
+    {
+      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+      PRINT_REG (rtl, 0, asm_out_file);
+    }
+  fputc ('\n', asm_out_file);
+}
+
 /* The following routine is a nice and simple transducer.  It converts the
    RTL for a variable or parameter (resident in memory) into an equivalent
    Dwarf representation of a mechanism for getting the address of that same
@@ -1452,15 +1540,25 @@ output_mem_loc_descriptor (rtl)
 
        /* Whenever a register number forms a part of the description of
           the method for calculating the (dynamic) address of a memory
-          resident object, Dwarf rules require the register number to
+          resident object, DWARF rules require the register number to
           be referred to as a "base register".  This distinction is not
           based in any way upon what category of register the hardware
           believes the given register belongs to.  This is strictly
-          Dwarf terminology we're dealing with here.  */
+          DWARF terminology we're dealing with here.
+
+          Note that in cases where the location of a memory-resident data
+          object could be expressed as:
+
+                   OP_ADD (OP_BASEREG (basereg), OP_CONST (0))
+
+          the actual DWARF location descriptor that we generate may just
+          be OP_BASEREG (basereg).  This may look deceptively like the
+          object in question was allocated to a register (rather than
+          in memory) so DWARF consumers need to be aware of the subtle
+          distinction between OP_REG and OP_BASEREG.  */
 
        ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_BASEREG);
-        ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
-                               DBX_REGISTER_NUMBER (REGNO (rtl)));
+       output_reg_number (rtl);
        break;
 
       case MEM:
@@ -1515,8 +1613,7 @@ output_loc_descriptor (rtl)
 
     case REG:
        ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_REG);
-        ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
-                               DBX_REGISTER_NUMBER (REGNO (rtl)));
+       output_reg_number (rtl);
        break;
 
     case MEM:
@@ -1776,7 +1873,7 @@ field_byte_offset (decl)
      for the declared type of the field) which it can possibly use, subject
      to the condition that there is still enough available space remaining
      in the containing object (when allocated at the selected point) to
-     fully accomodate all of the bits of the bit-field itself.
+     fully accommodate all of the bits of the bit-field itself.
 
      This simple rule makes it obvious why GCC allocates 8 bytes for each
      object of the structure type shown above.  When looking for a place to
@@ -1855,13 +1952,27 @@ location_attribute (rtl)
   /* Handle a special case.  If we are about to output a location descriptor
      for a variable or parameter which has been optimized out of existence,
      don't do that.  Instead we output a zero-length location descriptor
-     value as part of the location attribute.  Note that we cannot simply
-     suppress the entire location attribute, because the absence of a
-     location attribute in certain kinds of DIEs is used to indicate some-
-     thing entirely different... i.e. that the DIE represents an object
-     declaration, but not a definition.  So sayeth the PLSIG.  */
+     value as part of the location attribute.
+
+     A variable which has been optimized out of existence will have a
+     DECL_RTL value which denotes a pseudo-reg.
+
+     Currently, in some rare cases, variables can have DECL_RTL values
+     which look like (MEM (REG pseudo-reg#)).  These cases are due to
+     bugs elsewhere in the compiler.  We treat such cases
+     as if the variable(s) in question had been optimized out of existence.
+
+     Note that in all cases where we wish to express the fact that a
+     variable has been optimized out of existence, we do not simply
+     suppress the generation of the entire location attribute because
+     the absence of a location attribute in certain kinds of DIEs is
+     used to indicate something else entirely... i.e. that the DIE
+     represents an object declaration, but not a definition.  So sayeth
+     the PLSIG.
+  */
 
-  if (! is_pseudo_reg (rtl))
+  if (! is_pseudo_reg (rtl)
+      && (GET_CODE (rtl) != MEM || ! is_pseudo_reg (XEXP (rtl, 0))))
     output_loc_descriptor (eliminate_regs (rtl, 0, NULL_RTX));
 
   ASM_OUTPUT_LABEL (asm_out_file, end_label);
@@ -2009,68 +2120,109 @@ location_or_const_value_attribute (decl)
     return;
 
   if ((TREE_CODE (decl) != VAR_DECL) && (TREE_CODE (decl) != PARM_DECL))
-    abort ();
+    {
+      /* Should never happen.  */
+      abort ();
+      return;
+    }
 
-  /* Existing Dwarf debuggers need and expect the location descriptors for
-     formal parameters to reflect either the place where the parameters get
-     passed (if they are passed on the stack and in memory) or else the
-     (preserved) registers which the parameters get copied to during the
-     function prologue.
-
-     At least this is the way things are for most common CISC machines
-     (e.g. x86 and m68k) where parameters are passed in the stack, and for
-     most common RISC machines (e.g. i860 and m88k) where parameters are
-     passed in registers.
-
-     The rules for Sparc are a little weird for some reason.  The DWARF
-     generated by the USL C compiler for the Sparc/svr4 reference port says
-     that the parameters are passed in the stack.  I haven't figured out
-     how to duplicate that behavior here (for the Sparc) yet, or even if
-     I really need to.
-
-     Note that none of this is clearly spelled out in the current Dwarf
-     version 1 specification, but it's obvious if you look at the output of
-     the CI5 compiler, or if you try to use the svr4 SDB debugger.  Hopefully,
-     a later version of the Dwarf specification will clarify this.  For now,
-     we just need to generate the right thing.  Note that Dwarf version 2
-     will provide us with a means to describe *all* of the locations in which
-     a given variable or parameter resides (and the PC ranges over which it
-     occupies each one), but for now we can only describe one "location"
-     for each formal parameter passed, and so we just try to mimic existing
-     practice as much as possible.
+  /* Here we have to decide where we are going to say the parameter "lives"
+     (as far as the debugger is concerned).  We only have a couple of choices.
+     GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.  DECL_RTL
+     normally indicates where the parameter lives during most of the activa-
+     tion of the function.  If optimization is enabled however, this could
+     be either NULL or else a pseudo-reg.  Both of those cases indicate that
+     the parameter doesn't really live anywhere (as far as the code generation
+     parts of GCC are concerned) during most of the function's activation.
+     That will happen (for example) if the parameter is never referenced
+     within the function.
+
+     We could just generate a location descriptor here for all non-NULL
+     non-pseudo values of DECL_RTL and ignore all of the rest, but we can
+     be a little nicer than that if we also consider DECL_INCOMING_RTL in
+     cases where DECL_RTL is NULL or is a pseudo-reg.
+
+     Note however that we can only get away with using DECL_INCOMING_RTL as
+     a backup substitute for DECL_RTL in certain limited cases.  In cases
+     where DECL_ARG_TYPE(decl) indicates the same type as TREE_TYPE(decl)
+     we can be sure that the parameter was passed using the same type as it
+     is declared to have within the function, and that its DECL_INCOMING_RTL
+     points us to a place where a value of that type is passed.  In cases
+     where DECL_ARG_TYPE(decl) and TREE_TYPE(decl) are different types
+     however, we cannot (in general) use DECL_INCOMING_RTL as a backup
+     substitute for DECL_RTL because in these cases, DECL_INCOMING_RTL
+     points us to a value of some type which is *different* from the type
+     of the parameter itself.  Thus, if we tried to use DECL_INCOMING_RTL
+     to generate a location attribute in such cases, the debugger would
+     end up (for example) trying to fetch a `float' from a place which
+     actually contains the first part of a `double'.  That would lead to
+     really incorrect and confusing output at debug-time, and we don't
+     want that now do we?
+
+     So in general, we DO NOT use DECL_INCOMING_RTL as a backup for DECL_RTL
+     in cases where DECL_ARG_TYPE(decl) != TREE_TYPE(decl).  There are a
+     couple of cute exceptions however.  On little-endian machines we can
+     get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE(decl) is
+     not the same as TREE_TYPE(decl) but only when DECL_ARG_TYPE(decl) is
+     an integral type which is smaller than TREE_TYPE(decl).  These cases
+     arise when (on a little-endian machine) a non-prototyped function has
+     a parameter declared to be of type `short' or `char'.  In such cases,
+     TREE_TYPE(decl) will be `short' or `char', DECL_ARG_TYPE(decl) will be
+     `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
+     passed `int' value.  If the debugger then uses that address to fetch a
+     `short' or a `char' (on a little-endian machine) the result will be the
+     correct data, so we allow for such exceptional cases below.
+
+     Note that our goal here is to describe the place where the given formal
+     parameter lives during most of the function's activation (i.e. between
+     the end of the prologue and the start of the epilogue).  We'll do that
+     as best as we can.  Note however that if the given formal parameter is
+     modified sometime during the execution of the function, then a stack
+     backtrace (at debug-time) will show the function as having been called
+     with the *new* value rather than the value which was originally passed
+     in.  This happens rarely enough that it is not a major problem, but it
+     *is* a problem, and I'd like to fix it.  A future version of dwarfout.c
+     may generate two additional attributes for any given TAG_formal_parameter
+     DIE which will describe the "passed type" and the "passed location" for
+     the given formal parameter in addition to the attributes we now generate
+     to indicate the "declared type" and the "active location" for each
+     parameter.  This additional set of attributes could be used by debuggers
+     for stack backtraces.
+
+     Separately, note that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL
+     can be NULL also.  This happens (for example) for inlined-instances of
+     inline function formal parameters which are never referenced.  This really
+     shouldn't be happening.  All PARM_DECL nodes should get valid non-NULL
+     DECL_INCOMING_RTL values, but integrate.c doesn't currently generate
+     these values for inlined instances of inline function parameters, so
+     when we see such cases, we are just SOL (shit-out-of-luck) for the time
+     being (until integrate.c gets fixed).
   */
 
-  if (TREE_CODE (decl) != PARM_DECL)
-    /*  If this decl is not a formal parameter, just use DECL_RTL.  */
-    rtl = DECL_RTL (decl);
-  else
-    {
-      if (GET_CODE (DECL_INCOMING_RTL (decl)) == MEM)
-        /* Parameter was passed in memory, so say that's where it lives.  */
-       rtl = DECL_INCOMING_RTL (decl);
-      else
-       {
-          /* Parameter was passed in a register, so say it lives in the
-            register it will be copied to during the prologue.  */
-          rtl = DECL_RTL (decl);
-
-         /* Note that in cases where the formal parameter is never used
-            and where this compilation is done with -O, the copying of
-            of an incoming register parameter to another register (in
-            the prologue) can be totally optimized away.  (In such cases
-            the DECL_RTL will indicate a pseudo-register.)  We could just
-            use the DECL_RTL (as we normally do for register parameters)
-            in these cases, but if we did that, we would end up generating
-            a null location descriptor.  (See `location_attribute' above.)
-            That would be acceptable (according to the DWARF spec) but it
-            is probably more useful to say that the formal resides where
-            it was passed instead of saying that it resides nowhere.  */
-         if (is_pseudo_reg (rtl))
-           rtl = DECL_INCOMING_RTL (decl);
-       }
-    }
+  /* Use DECL_RTL as the "location" unless we find something better.  */
+  rtl = DECL_RTL (decl);
+
+  if (TREE_CODE (decl) == PARM_DECL)
+    if (rtl == NULL_RTX || is_pseudo_reg (rtl))
+      {
+       /* This decl represents a formal parameter which was optimized out.  */
+        register tree declared_type = type_main_variant (TREE_TYPE (decl));
+        register tree passed_type = type_main_variant (DECL_ARG_TYPE (decl));
 
-  if (rtl == NULL)
+       /* Note that DECL_INCOMING_RTL may be NULL in here, but we handle
+          *all* cases where (rtl == NULL_RTX) just below.  */
+
+       if (declared_type == passed_type)
+         rtl = DECL_INCOMING_RTL (decl);
+#if (BYTES_BIG_ENDIAN == 0)
+       else
+         if (TREE_CODE (declared_type) == INTEGER_TYPE)
+           if (TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type))
+             rtl = DECL_INCOMING_RTL (decl);
+#endif /* (BYTES_BIG_ENDIAN == 0) */
+      }
+
+  if (rtl == NULL_RTX)
     return;
 
   switch (GET_CODE (rtl))
@@ -2301,6 +2453,7 @@ byte_size_attribute (tree_node)
       case ENUMERAL_TYPE:
       case RECORD_TYPE:
       case UNION_TYPE:
+      case QUAL_UNION_TYPE:
        size = int_size_in_bytes (tree_node);
        break;
 
@@ -2471,6 +2624,26 @@ high_pc_attribute (asm_high_label)
   ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_high_label);
 }
 
+/* Generate an AT_body_begin attribute for a subroutine DIE.  */
+
+inline void
+body_begin_attribute (asm_begin_label)
+     register char *asm_begin_label;
+{
+  ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_body_begin);
+  ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_begin_label);
+}
+
+/* Generate an AT_body_end attribute for a subroutine DIE.  */
+
+inline void
+body_end_attribute (asm_end_label)
+     register char *asm_end_label;
+{
+  ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_body_end);
+  ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_end_label);
+}
+
 /* Generate an AT_language attribute given a LANG value.  These attributes
    are used only within TAG_compile_unit DIEs.  */
 
@@ -2490,9 +2663,7 @@ member_attribute (context)
 
   /* Generate this attribute only for members in C++.  */
 
-  if (context != NULL
-      && (TREE_CODE (context) == RECORD_TYPE
-         || TREE_CODE (context) == UNION_TYPE))
+  if (context != NULL && is_tagged_type (context))
     {
       ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_member);
       sprintf (label, TYPE_NAME_FMT, TYPE_UID (context));
@@ -2720,7 +2891,16 @@ type_attribute (type, decl_const, decl_volatile)
     if (root_type_modified)
        mod_u_d_type_attribute (type, decl_const, decl_volatile);
     else
-       user_def_type_attribute (type);
+       /* We have to get the type_main_variant here (and pass that to the
+          `user_def_type_attribute' routine) because the ..._TYPE node we
+          have might simply be a *copy* of some original type node (where
+          the copy was created to help us keep track of typedef names)
+          and that copy might have a different TYPE_UID from the original
+          ..._TYPE node.  (Note that when `equate_type_number_to_die_number'
+          is labeling a given type DIE for future reference, it always and
+          only creates labels for DIEs representing *main variants*, and it
+          never even knows about non-main-variants.)  */
+       user_def_type_attribute (type_main_variant (type));
 }
 
 /* Given a tree pointer to a struct, class, union, or enum type node, return
@@ -3029,11 +3209,15 @@ output_global_subroutine_die (arg)
     {
       if (! DECL_EXTERNAL (decl))
        {
-         char func_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+         char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
          low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
-         sprintf (func_end_label, FUNC_END_LABEL_FMT, current_funcdef_number);
-         high_pc_attribute (func_end_label);
+         sprintf (label, FUNC_END_LABEL_FMT, current_funcdef_number);
+         high_pc_attribute (label);
+         sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+         body_begin_attribute (label);
+         sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
+         body_end_attribute (label);
        }
     }
 }
@@ -3267,6 +3451,8 @@ output_compile_unit_die (arg)
 
   if (strcmp (language_string, "GNU C++") == 0)
     language_attribute (LANG_C_PLUS_PLUS);
+  else if (strcmp (language_string, "GNU Ada") == 0)
+    language_attribute (LANG_ADA83);
   else if (flag_traditional)
     language_attribute (LANG_C);
   else
@@ -3367,11 +3553,15 @@ output_local_subroutine_die (arg)
 
       if (TREE_ASM_WRITTEN (decl))
        {
-         char func_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+         char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
          low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
-         sprintf (func_end_label, FUNC_END_LABEL_FMT, current_funcdef_number);
-         high_pc_attribute (func_end_label);
+         sprintf (label, FUNC_END_LABEL_FMT, current_funcdef_number);
+         high_pc_attribute (label);
+         sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+         body_begin_attribute (label);
+         sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
+         body_end_attribute (label);
        }
     }
 }
@@ -3626,32 +3816,22 @@ pend_type (type)
 
 /* Return non-zero if it is legitimate to output DIEs to represent a
    given type while we are generating the list of child DIEs for some
-   DIE associated with a given scope.
-
-   This function returns non-zero if *either* of the following two conditions
-   is satisfied:
-
-        o      the type actually belongs to the given scope (as evidenced
-               by its TYPE_CONTEXT value), or
+   DIE (e.g. a function or lexical block DIE) associated with a given scope.
 
-        o      the type is anonymous, and the `scope' in question is *not*
-               a RECORD_TYPE or UNION_TYPE.
-
-   In theory, we should be able to generate DIEs for anonymous types
-   *anywhere* (since the scope of an anonymous type is irrelevant)
-   however svr4 SDB doesn't want to see other type DIEs within the
-   lists of child DIEs for a TAG_structure_type or TAG_union_type DIE.
+   See the comments within the function for a description of when it is
+   considered legitimate to output DIEs for various kinds of types.
 
    Note that TYPE_CONTEXT(type) may be NULL (to indicate global scope)
    or it may point to a BLOCK node (for types local to a block), or to a
    FUNCTION_DECL node (for types local to the heading of some function
    definition), or to a FUNCTION_TYPE node (for types local to the
    prototyped parameter list of a function type specification), or to a
-   RECORD_TYPE or UNION_TYPE node (in the case of C++ nested types).
+   RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node
+   (in the case of C++ nested types).
 
    The `scope' parameter should likewise be NULL or should point to a
    BLOCK node, a FUNCTION_DECL node, a FUNCTION_TYPE node, a RECORD_TYPE
-   node, or a UNION_TYPE node.
+   node, a UNION_TYPE node, or a QUAL_UNION_TYPE node.
 
    This function is used only for deciding when to "pend" and when to
    "un-pend" types to/from the pending_types_list.
@@ -3662,28 +3842,38 @@ pend_type (type)
    It order to delay the production of DIEs representing types of formal
    parameters, callers of this function supply `fake_containing_scope' as
    the `scope' parameter to this function.  Given that fake_containing_scope
-   is *not* the containing scope for *any* other type, the desired effect
-   is achieved, i.e. output of DIEs representing types is temporarily
-   suspended, and any type DIEs which would have been output otherwise
-   are instead placed onto the pending_types_list.  Later on, we can force
-   these (temporarily pended) types to be output simply by calling
+   is a tagged type which is *not* the containing scope for *any* other type,
+   the desired effect is achieved, i.e. output of DIEs representing types
+   is temporarily suspended, and any type DIEs which would have otherwise
+   been output are instead placed onto the pending_types_list.  Later on,
+   we force these (temporarily pended) types to be output simply by calling
    `output_pending_types_for_scope' with an actual argument equal to the
    true scope of the types we temporarily pended.
 */
 
-static int
+inline int
 type_ok_for_scope (type, scope)
     register tree type;
     register tree scope;
 {
-  return (TYPE_CONTEXT (type) == scope
-         || (TYPE_NAME (type) == NULL
-             && TREE_CODE (scope) != RECORD_TYPE
-             && TREE_CODE (scope) != UNION_TYPE));
+  /* Tagged types (i.e. struct, union, and enum types) must always be
+     output only in the scopes where they actually belong (or else the
+     scoping of their own tag names and the scoping of their member
+     names will be incorrect).  Non-tagged-types on the other hand can
+     generally be output anywhere, except that svr4 SDB really doesn't
+     want to see them nested within struct or union types, so here we
+     say it is always OK to immediately output any such a (non-tagged)
+     type, so long as we are not within such a context.  Note that the
+     only kinds of non-tagged types which we will be dealing with here
+     (for C and C++ anyway) will be array types and function types.  */
+
+  return is_tagged_type (type)
+        ? (TYPE_CONTEXT (type) == scope)
+        : (scope == NULL_TREE || ! is_tagged_type (scope));
 }
 
 /* Output any pending types (from the pending_types list) which we can output
-   now (given the limitations of the scope that we are working on now).
+   now (taking into account the scope that we are working on now).
 
    For each type output, remove the given type from the pending_types_list
    *before* we try to output it.
@@ -3742,7 +3932,7 @@ output_type (type, containing_scope)
      of this type (i.e. without any const or volatile qualifiers) so get
      the main variant (i.e. the unqualified version) of this type now.  */
 
-  type = TYPE_MAIN_VARIANT (type);
+  type = type_main_variant (type);
 
   if (TREE_ASM_WRITTEN (type))
     return;
@@ -3764,7 +3954,7 @@ output_type (type, containing_scope)
       case POINTER_TYPE:
       case REFERENCE_TYPE:
        /* For these types, all that is required is that we output a DIE
-          (or a set of DIEs) to represent that "basis" type.  */
+          (or a set of DIEs) to represent the "basis" type.  */
        output_type (TREE_TYPE (type), containing_scope);
        break;
 
@@ -3826,15 +4016,16 @@ output_type (type, containing_scope)
       case ENUMERAL_TYPE:
       case RECORD_TYPE:
       case UNION_TYPE:
+      case QUAL_UNION_TYPE:
 
        /* For a non-file-scope tagged type, we can always go ahead and
           output a Dwarf description of this type right now, even if
           the type in question is still incomplete, because if this
           local type *was* ever completed anywhere within its scope,
           that complete definition would already have been attached to
-          this RECORD_TYPE, UNION_TYPE or ENUMERAL_TYPE node by the
-          time we reach this point.  That's true because of the way the
-          front-end does its processing of file-scope declarations (of
+          this RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE or ENUMERAL_TYPE
+          node by the time we reach this point.  That's true because of the
+          way the front-end does its processing of file-scope declarations (of
           functions and class types) within which other types might be
           nested.  The C and C++ front-ends always gobble up such "local
           scope" things en-mass before they try to output *any* debugging
@@ -3879,6 +4070,7 @@ output_type (type, containing_scope)
            break;
 
          case UNION_TYPE:
+         case QUAL_UNION_TYPE:
            output_die (output_union_type_die, type);
            break;
 
@@ -3943,6 +4135,12 @@ output_type (type, containing_scope)
                }
            }
 
+           /* RECORD_TYPEs, UNION_TYPEs, and QUAL_UNION_TYPEs are themselves
+              scopes (at least in C++) so we must now output any nested
+              pending types which are local just to this type.  */
+
+           output_pending_types_for_scope (type);
+
            end_sibling_chain ();       /* Terminate member chain.  */
          }
 
@@ -3978,7 +4176,7 @@ output_tagged_type_instantiation (type)
      sure that we have the main variant (i.e. the unqualified version) of
      this type now.  */
 
-  assert (type == TYPE_MAIN_VARIANT (type));
+  assert (type == type_main_variant (type));
 
   assert (TREE_ASM_WRITTEN (type));
 
@@ -3996,6 +4194,7 @@ output_tagged_type_instantiation (type)
        break;
 
       case UNION_TYPE:
+      case QUAL_UNION_TYPE:
        output_die (output_inlined_union_type_die, type);
        break;
 
@@ -4047,9 +4246,7 @@ output_block (stmt)
         not represent a "body block inlining" before trying to set the
         `must_output_die' flag.  */
 
-      if (origin != NULL
-         && origin_code == BLOCK
-         && ! is_body_block (origin))
+      if (origin == NULL || ! is_body_block (origin))
        {
          /* Determine if this block directly contains any "significant"
             local declarations which we will need to output DIEs for.  */
@@ -4144,6 +4341,12 @@ output_decl (decl, containing_scope)
      register tree decl;
      register tree containing_scope;
 {
+  /* Make a note of the decl node we are going to be working on.  We may
+     need to give the user the source coordinates of where it appeared in
+     case we notice (later on) that something about it looks screwy.  */
+
+  dwarf_last_decl = decl;
+
   if (TREE_CODE (decl) == ERROR_MARK)
     return;
 
@@ -4165,11 +4368,11 @@ output_decl (decl, containing_scope)
 
     case FUNCTION_DECL:
       /* If we are in terse mode, don't output any DIEs to represent
-        mere external function declarations.  Also, if we are conforming
+        mere function declarations.  Also, if we are conforming
         to the DWARF version 1 specification, don't output DIEs for
-        mere external function declarations.  */
+        mere function declarations.  */
 
-      if (DECL_EXTERNAL (decl))
+      if (DECL_INITIAL (decl) == NULL_TREE)
 #if (DWARF_VERSION > 1)
        if (debug_info_level <= DINFO_LEVEL_TERSE)
 #endif
@@ -4212,11 +4415,11 @@ output_decl (decl, containing_scope)
         ends with a void_type_node then there should *not* be an ellipsis
         at the end.  */
 
-      /* In the case where we are describing an external function, all
+      /* In the case where we are describing a mere function declaration, all
         we need to do here (and all we *can* do here) is to describe
         the *types* of its formal parameters.  */
 
-      if (DECL_EXTERNAL (decl))
+      if (DECL_INITIAL (decl) == NULL_TREE)
        output_formal_types (TREE_TYPE (decl));
       else
        {
@@ -4557,17 +4760,37 @@ dwarfout_file_scope_decl (decl, set_finalizing)
       if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl))
         return;
 
-      /* Ignore this FUNCTION_DECL if it refers to a file-scope extern
-        function declaration and if the declaration was never even
-        referenced from within this entire compilation unit.  We
-        suppress these DIEs in order to save space in the .debug section
-        (by eliminating entries which are probably useless).  Note that
-        we must not suppress block-local extern declarations (whether
-        used or not) because that would screw-up the debugger's name
-        lookup mechanism and cause it to miss things which really ought
-        to be in scope at a given point.  */
-
-      if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
+      /* What we would really like to do here is to filter out all mere
+        file-scope declarations of file-scope functions which are never
+        referenced later within this translation unit (and keep all of
+        ones that *are* referenced later on) but we aren't clarvoiant,
+        so we have no idea which functions will be referenced in the
+        future (i.e. later on within the current translation unit).
+        So here we just ignore all file-scope function declarations
+        which are not also definitions.  If and when the debugger needs
+        to know something about these funcstion, it wil have to hunt
+        around and find the DWARF information associated with the
+        *definition* of the function.
+
+        Note that we can't just check `DECL_EXTERNAL' to find out which
+        FUNCTION_DECL nodes represent definitions and which ones represent
+        mere declarations.  We have to check `DECL_INITIAL' instead.  That's
+        because the C front-end supports some weird semantics for "extern
+        inline" function definitions.  These can get inlined within the
+        current translation unit (an thus, we need to generate DWARF info
+        for their abstract instances so that the DWARF info for the
+        concrete inlined instances can have something to refer to) but
+        the compiler never generates any out-of-lines instances of such
+        things (despite the fact that they *are* definitions).  The
+        important point is that the C front-end marks these "extern inline"
+        functions as DECL_EXTERNAL, but we need to generate DWARf for them
+        anyway.
+
+        Note that the C++ front-end also plays some similar games for inline
+        function definitions appearing within include files which also
+        contain `#pragma interface' pragmas.  */
+
+      if (DECL_INITIAL (decl) == NULL_TREE)
        return;
 
       if (TREE_PUBLIC (decl)
@@ -4650,9 +4873,18 @@ dwarfout_file_scope_decl (decl, set_finalizing)
       break;
 
     case TYPE_DECL:
-      /* Don't generate any DIEs to represent the standard built-in types.  */
-
-      if (DECL_SOURCE_LINE (decl) == 0)
+      /* Don't bother trying to generate any DIEs to represent any of the
+        normal built-in types for the language we are compiling, except
+        in cases where the types in question are *not* DWARF fundamental
+        types.  We make an exception in the case of non-fundamental types
+        for the sake of objective C (and perhaps C++) because the GNU
+        front-ends for these languages may in fact create certain "built-in"
+        types which are (for example) RECORD_TYPEs.  In such cases, we
+        really need to output these (non-fundamental) types because other
+        DIEs may contain references to them.  */
+
+      if (DECL_SOURCE_LINE (decl) == 0
+         && type_is_fundamental (TREE_TYPE (decl)))
        return;
 
       /* If we are in terse mode, don't generate any DIEs to represent
@@ -4746,6 +4978,33 @@ dwarfout_label (insn)
     }
 }
 
+/* Output a marker (i.e. a label) for the point in the generated code where
+   the real body of the function begins (after parameters have been moved
+   to their home locations).  */
+
+void
+dwarfout_begin_function ()
+{
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+  text_section ();
+  sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+  ASM_OUTPUT_LABEL (asm_out_file, label);
+}
+
+/* Output a marker (i.e. a label) for the point in the generated code where
+   the real body of the function ends (just before the epilogue code).  */
+
+void
+dwarfout_end_function ()
+{
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+  text_section ();
+  sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
+  ASM_OUTPUT_LABEL (asm_out_file, label);
+}
+
 /* Output a marker (i.e. a label) for the absolute end of the generated code
    for a function definition.  This gets called *after* the epilogue code
    has been generated. */
@@ -5082,12 +5341,14 @@ dwarfout_init (asm_out_file, main_input_filename)
   ASM_OUTPUT_LABEL (asm_out_file, DATA_BEGIN_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
 
+#if 0 /* GNU C doesn't currently use .data1.  */
   /* Output a starting label for the .data1 section.  */
 
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_PUSH_SECTION (asm_out_file, DATA1_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, DATA1_BEGIN_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
+#endif
 
   /* Output a starting label for the .rodata section.  */
 
@@ -5096,12 +5357,14 @@ dwarfout_init (asm_out_file, main_input_filename)
   ASM_OUTPUT_LABEL (asm_out_file, RODATA_BEGIN_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
 
+#if 0 /* GNU C doesn't currently use .rodata1.  */
   /* Output a starting label for the .rodata1 section.  */
 
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_PUSH_SECTION (asm_out_file, RODATA1_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, RODATA1_BEGIN_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
+#endif
 
   /* Output a starting label for the .bss section.  */
 
@@ -5259,12 +5522,14 @@ dwarfout_finish ()
   ASM_OUTPUT_LABEL (asm_out_file, DATA_END_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
 
+#if 0 /* GNU C doesn't currently use .data1.  */
   /* Output a terminator label for the .data1 section.  */
 
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_PUSH_SECTION (asm_out_file, DATA1_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, DATA1_END_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
+#endif
 
   /* Output a terminator label for the .rodata section.  */
 
@@ -5273,12 +5538,14 @@ dwarfout_finish ()
   ASM_OUTPUT_LABEL (asm_out_file, RODATA_END_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
 
+#if 0 /* GNU C doesn't currently use .rodata1.  */
   /* Output a terminator label for the .rodata1 section.  */
 
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_PUSH_SECTION (asm_out_file, RODATA1_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, RODATA1_END_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
+#endif
 
   /* Output a terminator label for the .bss section.  */
 
@@ -5353,17 +5620,21 @@ dwarfout_finish ()
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, DATA_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, DATA_END_LABEL, DATA_BEGIN_LABEL);
 
+#if 0 /* GNU C doesn't currently use .data1.  */
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, DATA1_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, DATA1_END_LABEL,
                                             DATA1_BEGIN_LABEL);
+#endif
 
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, RODATA_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, RODATA_END_LABEL,
                                             RODATA_BEGIN_LABEL);
 
+#if 0 /* GNU C doesn't currently use .rodata1.  */
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, RODATA1_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, RODATA1_END_LABEL,
                                             RODATA1_BEGIN_LABEL);
+#endif
 
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, BSS_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, BSS_END_LABEL, BSS_BEGIN_LABEL);