-/* This file contains code written by Ron Guilmette (rfg@ncd.com) for
- 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.
+/* Output Dwarf format symbol table information from the GNU C compiler.
+ Copyright (C) 1992, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@monkeys.com) of Network Computing Devices.
This file is part of GNU CC.
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. */
#include "config.h"
#include "output.h"
#include "defaults.h"
-#ifndef DWARF_VERSION
-#define DWARF_VERSION 1
-#endif
-
/* #define NDEBUG 1 */
#include "assert.h"
/* Note that the implementation of C++ support herein is (as yet) unfinished.
If you want to try to complete it, more power to you. */
-#if defined(__GNUC__) && (NDEBUG == 1)
-#define inline static inline
-#else
-#define inline static
+#if !defined(__GNUC__) || (NDEBUG != 1)
+#define inline
#endif
/* How to start an assembler comment. */
#define TYPE_USED_FOR_FUNCTION(tagged_type) (TYPE_SIZE (tagged_type) == 0)
+/* Define a macro which returns non-zero for a TYPE_DECL which was
+ implicitly generated for a tagged type.
+
+ Note that unlike the gcc front end (which generates a NULL named
+ TYPE_DECL node for each complete tagged type, each array type, and
+ each function type node created) the g++ front end generates a
+ _named_ TYPE_DECL node for each tagged type node created.
+ These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to
+ generate a DW_TAG_typedef DIE for them. */
+#define TYPE_DECL_IS_STUB(decl) \
+ (DECL_NAME (decl) == NULL \
+ || (DECL_ARTIFICIAL (decl) \
+ && is_tagged_type (TREE_TYPE (decl)) \
+ && decl == TYPE_STUB_DECL (TREE_TYPE (decl))))
+
extern int flag_traditional;
extern char *version_string;
extern char *language_string;
typedef struct filename_entry filename_entry;
-/* Pointer to an array of elements, each one having the structure above. */
+/* Pointer to an array of elements, each one having the structure above. */
static filename_entry *filename_table;
static unsigned next_block_number = 2;
-/* Counter to generate unique names for DIEs. */
+/* Counter to generate unique names for DIEs. */
static unsigned next_unused_dienum = 1;
static tree dwarf_last_decl;
+/* A flag indicating that we are emitting the member declarations of a
+ class, so member functions and variables should not be entirely emitted.
+ This is a kludge to avoid passing a second argument to output_*_die. */
+
+static int in_class;
+
/* Forward declarations for functions defined in this file. */
-static void output_type ();
-static void type_attribute ();
-static void output_decls_for_scope ();
-static void output_decl ();
-static unsigned lookup_filename ();
+static char *dwarf_tag_name PROTO((unsigned));
+static char *dwarf_attr_name PROTO((unsigned));
+static char *dwarf_stack_op_name PROTO((unsigned));
+static char *dwarf_typemod_name PROTO((unsigned));
+static char *dwarf_fmt_byte_name PROTO((unsigned));
+static char *dwarf_fund_type_name PROTO((unsigned));
+static tree decl_ultimate_origin PROTO((tree));
+static tree block_ultimate_origin PROTO((tree));
+static void output_unsigned_leb128 PROTO((unsigned long));
+static void output_signed_leb128 PROTO((long));
+static inline int is_body_block PROTO((tree));
+static int fundamental_type_code PROTO((tree));
+static tree root_type_1 PROTO((tree, int));
+static tree root_type PROTO((tree));
+static void write_modifier_bytes_1 PROTO((tree, int, int, int));
+static void write_modifier_bytes PROTO((tree, int, int));
+static inline int type_is_fundamental PROTO((tree));
+static void equate_decl_number_to_die_number PROTO((tree));
+static inline void equate_type_number_to_die_number PROTO((tree));
+static void output_reg_number PROTO((rtx));
+static void output_mem_loc_descriptor PROTO((rtx));
+static void output_loc_descriptor PROTO((rtx));
+static void output_bound_representation PROTO((tree, unsigned, int));
+static void output_enumeral_list PROTO((tree));
+static inline unsigned ceiling PROTO((unsigned, unsigned));
+static inline tree field_type PROTO((tree));
+static inline unsigned simple_type_align_in_bits PROTO((tree));
+static inline unsigned simple_type_size_in_bits PROTO((tree));
+static unsigned field_byte_offset PROTO((tree));
+static inline void sibling_attribute PROTO((void));
+static void location_attribute PROTO((rtx));
+static void data_member_location_attribute PROTO((tree));
+static void const_value_attribute PROTO((rtx));
+static void location_or_const_value_attribute PROTO((tree));
+static inline void name_attribute PROTO((char *));
+static inline void fund_type_attribute PROTO((unsigned));
+static void mod_fund_type_attribute PROTO((tree, int, int));
+static inline void user_def_type_attribute PROTO((tree));
+static void mod_u_d_type_attribute PROTO((tree, int, int));
+static inline void ordering_attribute PROTO((unsigned));
+static void subscript_data_attribute PROTO((tree));
+static void byte_size_attribute PROTO((tree));
+static inline void bit_offset_attribute PROTO((tree));
+static inline void bit_size_attribute PROTO((tree));
+static inline void element_list_attribute PROTO((tree));
+static inline void stmt_list_attribute PROTO((char *));
+static inline void low_pc_attribute PROTO((char *));
+static inline void high_pc_attribute PROTO((char *));
+static inline void body_begin_attribute PROTO((char *));
+static inline void body_end_attribute PROTO((char *));
+static inline void langauge_attribute PROTO((unsigned));
+static inline void member_attribute PROTO((tree));
+static inline void string_length_attribute PROTO((tree));
+static inline void comp_dir_attribute PROTO((char *));
+static inline void sf_names_attribute PROTO((char *));
+static inline void src_info_attribute PROTO((char *));
+static inline void mac_info_attribute PROTO((char *));
+static inline void prototyped_attribute PROTO((tree));
+static inline void producer_attribute PROTO((char *));
+static inline void inline_attribute PROTO((tree));
+static inline void containing_type_attribute PROTO((tree));
+static inline void abstract_origin_attribute PROTO((tree));
+static inline void src_coords_attribute PROTO((unsigned, unsigned));
+static inline void pure_or_virtual_attribute PROTO((tree));
+static void name_and_src_coords_attributes PROTO((tree));
+static void type_attribute PROTO((tree, int, int));
+static char *type_tag PROTO((tree));
+static inline void dienum_push PROTO((void));
+static inline void dienum_pop PROTO((void));
+static inline tree member_declared_type PROTO((tree));
+static char *function_start_label PROTO((tree));
+static void output_array_type_die PROTO((void *));
+static void output_set_type_die PROTO((void *));
+static void output_entry_point_die PROTO((void *));
+static void output_inlined_enumeration_type_die PROTO((void *));
+static void output_inlined_structure_type_die PROTO((void *));
+static void output_inlined_union_type_die PROTO((void *));
+static void output_enumeration_type_die PROTO((void *));
+static void output_formal_parameter_die PROTO((void *));
+static void output_global_subroutine_die PROTO((void *));
+static void output_global_variable_die PROTO((void *));
+static void output_label_die PROTO((void *));
+static void output_lexical_block_die PROTO((void *));
+static void output_inlined_subroutine_die PROTO((void *));
+static void output_local_variable_die PROTO((void *));
+static void output_member_die PROTO((void *));
+static void output_pointer_type_die PROTO((void *));
+static void output_reference_type_die PROTO((void *));
+static void output_ptr_to_mbr_type_die PROTO((void *));
+static void output_compile_unit_die PROTO((void *));
+static void output_string_type_die PROTO((void *));
+static void output_structure_type_die PROTO((void *));
+static void output_local_subroutine_die PROTO((void *));
+static void output_subroutine_type_die PROTO((void *));
+static void output_typedef_die PROTO((void *));
+static void output_union_type_die PROTO((void *));
+static void output_unspecified_parameters_die PROTO((void *));
+static void output_padded_null_die PROTO((void *));
+static void output_die PROTO((void (*) (), void *));
+static void end_sibling_chain PROTO((void));
+static void output_formal_types PROTO((tree));
+static void pend_type PROTO((tree));
+static inline int type_of_for_scope PROTO((tree, tree));
+static void output_pending_types_for_scope PROTO((tree));
+static void output_type PROTO((tree, tree));
+static void output_tagged_type_instantiation PROTO((tree));
+static void output_block PROTO((tree, int));
+static void output_decls_for_scope PROTO((tree, int));
+static void output_decl PROTO((tree, tree));
+static void shuffle_filename_entry PROTO((filename_entry *));
+static void geneate_new_sfname_entry PROTO((void));
+static unsigned lookup_filename PROTO((char *));
+static void generate_srcinfo_entry PROTO((unsigned, unsigned));
+static void generate_macinfo_entry PROTO((char *, char *));
\f
/* Definitions of defaults for assembler-dependent names of various
pseudo-ops and section names.
section name must be enclosed in double quotes. (See sparcv4.h.) */
#ifndef PUSHSECTION_FORMAT
-#define PUSHSECTION_FORMAT "%s\t%s\n"
+#define PUSHSECTION_FORMAT "\t%s\t%s\n"
#endif
#ifndef DEBUG_SECTION
output operations.
If necessary, these may be overridden from within your tm.h file,
- but typically, you shouldn't need to override these. One known
- exception is ASM_OUTPUT_DEF which has to be different for stock
- sparc/svr4 assemblers.
-*/
+ but typically, you shouldn't need to override these. */
#ifndef ASM_OUTPUT_PUSH_SECTION
#define ASM_OUTPUT_PUSH_SECTION(FILE, SECTION) \
#ifndef ASM_OUTPUT_SOURCE_FILENAME
#define ASM_OUTPUT_SOURCE_FILENAME(FILE,NAME) \
- fprintf ((FILE), "\t%s\t\"%s\"\n", FILE_ASM_OP, NAME)
-#endif
-
-#ifndef ASM_OUTPUT_DEF
-#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \
- do { fprintf ((FILE), "\t%s\t", SET_ASM_OP); \
- assemble_name (FILE, LABEL1); \
- fprintf (FILE, ","); \
- assemble_name (FILE, LABEL2); \
- fprintf (FILE, "\n"); \
+ do { fprintf (FILE, "\t%s\t", FILE_ASM_OP); \
+ output_quoted_string (FILE, NAME); \
+ fputc ('\n', FILE); \
} while (0)
#endif
do { \
fprintf ((FILE), "\t%s\t0x%x", \
UNALIGNED_SHORT_ASM_OP, (unsigned) TAG); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_tag_name (TAG)); \
fputc ('\n', (FILE)); \
do { \
fprintf ((FILE), "\t%s\t0x%x", \
UNALIGNED_SHORT_ASM_OP, (unsigned) ATTR); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_attr_name (ATTR)); \
fputc ('\n', (FILE)); \
#define ASM_OUTPUT_DWARF_STACK_OP(FILE,OP) \
do { \
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) OP); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_stack_op_name (OP)); \
fputc ('\n', (FILE)); \
do { \
fprintf ((FILE), "\t%s\t0x%x", \
UNALIGNED_SHORT_ASM_OP, (unsigned) FT); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_fund_type_name (FT)); \
fputc ('\n', (FILE)); \
#define ASM_OUTPUT_DWARF_FMT_BYTE(FILE,FMT) \
do { \
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) FMT); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_fmt_byte_name (FMT)); \
fputc ('\n', (FILE)); \
#define ASM_OUTPUT_DWARF_TYPE_MODIFIER(FILE,MOD) \
do { \
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) MOD); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_typemod_name (MOD)); \
fputc ('\n', (FILE)); \
\f
/************************ general utility functions **************************/
-inline char *
-xstrdup (s)
- register char *s;
-{
- register char *p = (char *) xmalloc (strlen (s) + 1);
-
- strcpy (p, s);
- return p;
-}
-
inline int
is_pseudo_reg (rtl)
register rtx 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
default: return "FMT_<unknown>";
}
}
+
static char *
dwarf_fund_type_name (ft)
register unsigned ft;
case FT_unsigned_int32: return "FT_unsigned_int32";
case FT_int64: return "FT_int64";
case FT_signed_int64: return "FT_signed_int64";
- case FT_unsigned_int64: return "FT_signed_int64";
+ case FT_unsigned_int64: return "FT_unsigned_int64";
case FT_real32: return "FT_real32";
case FT_real64: return "FT_real64";
}
}
+/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT
+ of a virtual function may refer to a base class, so we check the 'this'
+ parameter. */
+
+static tree
+decl_class_context (decl)
+ tree decl;
+{
+ tree context = NULL_TREE;
+ if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
+ context = DECL_CONTEXT (decl);
+ else
+ context = TYPE_MAIN_VARIANT
+ (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
+
+ if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't')
+ context = NULL_TREE;
+
+ return context;
+}
+
static void
output_unsigned_leb128 (value)
register unsigned long value;
if (value != 0) /* more bytes to follow */
byte |= 0x80;
fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) byte);
- if (flag_verbose_asm && value == 0)
+ if (flag_debug_asm && value == 0)
fprintf (asm_out_file, "\t%s ULEB128 number - value = %u",
ASM_COMMENT_START, orig_value);
fputc ('\n', asm_out_file);
more = 1;
}
fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) byte);
- if (flag_verbose_asm && more == 0)
+ if (flag_debug_asm && more == 0)
fprintf (asm_out_file, "\t%s SLEB128 number - value = %d",
ASM_COMMENT_START, orig_value);
fputc ('\n', asm_out_file);
FUNCTION_DECL node.
*/
-inline int
+static inline int
is_body_block (stmt)
register tree stmt;
{
qualifiers. */
static tree
-root_type (type)
+root_type_1 (type, count)
register tree type;
+ register int count;
{
- if (TREE_CODE (type) == ERROR_MARK)
+ /* Give up after searching 1000 levels, in case this is a recursive
+ pointer type. Such types are possible in Ada, but it is not possible
+ to represent them in DWARF1 debug info. */
+ if (count > 1000)
return error_mark_node;
switch (TREE_CODE (type))
case POINTER_TYPE:
case REFERENCE_TYPE:
- return TYPE_MAIN_VARIANT (root_type (TREE_TYPE (type)));
+ return root_type_1 (TREE_TYPE (type), count+1);
default:
- return TYPE_MAIN_VARIANT (type);
+ return type;
}
}
+static tree
+root_type (type)
+ register tree type;
+{
+ type = root_type_1 (type, 0);
+ if (type != error_mark_node)
+ type = type_main_variant (type);
+ return type;
+}
+
/* Given a pointer to an arbitrary ..._TYPE tree node, write out a sequence
of zero or more Dwarf "type-modifier" bytes applicable to the type. */
static void
-write_modifier_bytes (type, decl_const, decl_volatile)
+write_modifier_bytes_1 (type, decl_const, decl_volatile, count)
register tree type;
register int decl_const;
register int decl_volatile;
+ register int count;
{
if (TREE_CODE (type) == ERROR_MARK)
return;
+ /* Give up after searching 1000 levels, in case this is a recursive
+ pointer type. Such types are possible in Ada, but it is not possible
+ to represent them in DWARF1 debug info. */
+ if (count > 1000)
+ return;
+
if (TYPE_READONLY (type) || decl_const)
ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_const);
if (TYPE_VOLATILE (type) || decl_volatile)
{
case POINTER_TYPE:
ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_pointer_to);
- write_modifier_bytes (TREE_TYPE (type), 0, 0);
+ write_modifier_bytes_1 (TREE_TYPE (type), 0, 0, count+1);
return;
case REFERENCE_TYPE:
ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_reference_to);
- write_modifier_bytes (TREE_TYPE (type), 0, 0);
+ write_modifier_bytes_1 (TREE_TYPE (type), 0, 0, count+1);
return;
case ERROR_MARK:
return;
}
}
+
+static void
+write_modifier_bytes (type, decl_const, decl_volatile)
+ register tree type;
+ register int decl_const;
+ register int decl_volatile;
+{
+ write_modifier_bytes_1 (type, decl_const, decl_volatile, 0);
+}
\f
/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the
given input type is a Dwarf "fundamental" type. Otherwise return zero. */
-inline int
+static inline int
type_is_fundamental (type)
register tree type;
{
case METHOD_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
- case STRING_TYPE:
case FILE_TYPE:
case OFFSET_TYPE:
case LANG_TYPE:
simply by re-generating the alternative name from the ..._TYPE node's
UID number. */
-inline void
+static inline void
equate_type_number_to_die_number (type)
register tree 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);
}
fprintf (asm_out_file, "\t%s\t0x%x",
UNALIGNED_INT_ASM_OP, DBX_REGISTER_NUMBER (regno));
- if (flag_verbose_asm)
+ if (flag_debug_asm)
{
fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
PRINT_REG (rtl, 0, asm_out_file);
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, INTVAL (rtl));
break;
+ case MULT:
+ /* If a pseudo-reg is optimized away, it is possible for it to
+ be replaced with a MEM containing a multiply. Use a GNU extension
+ to describe it. */
+ output_mem_loc_descriptor (XEXP (rtl, 0));
+ output_mem_loc_descriptor (XEXP (rtl, 1));
+ ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_MULT);
+ break;
+
default:
abort ();
}
switch (TREE_CODE (bound))
{
- case ERROR_MARK:
- return;
+ case ERROR_MARK:
+ return;
/* All fixed-bounds are represented by INTEGER_CST nodes. */
- case INTEGER_CST:
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
- (unsigned) TREE_INT_CST_LOW (bound));
- break;
-
- /* Dynamic bounds may be represented by NOP_EXPR nodes containing
- SAVE_EXPR nodes. */
-
- case NOP_EXPR:
- bound = TREE_OPERAND (bound, 0);
- /* ... fall thru... */
-
- case SAVE_EXPR:
- {
- char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
- char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
-
- sprintf (begin_label, BOUND_BEGIN_LABEL_FMT,
- current_dienum, dim_num, u_or_l);
-
- sprintf (end_label, BOUND_END_LABEL_FMT,
- current_dienum, dim_num, u_or_l);
-
- ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label);
- ASM_OUTPUT_LABEL (asm_out_file, begin_label);
-
- /* If we are working on a bound for a dynamic dimension in C,
- the dynamic dimension in question had better have a static
- (zero) lower bound and a dynamic *upper* bound. */
+ case INTEGER_CST:
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
+ (unsigned) TREE_INT_CST_LOW (bound));
+ break;
- if (u_or_l != 'u')
- abort ();
+ default:
- /* If optimization is turned on, the SAVE_EXPRs that describe
- how to access the upper bound values are essentially bogus.
- They only describe (at best) how to get at these values at
- the points in the generated code right after they have just
- been computed. Worse yet, in the typical case, the upper
- bound values will not even *be* computed in the optimized
- code, so these SAVE_EXPRs are entirely bogus.
-
- In order to compensate for this fact, we check here to see
- if optimization is enabled, and if so, we effectively create
- an empty location description for the (unknown and unknowable)
- upper bound.
-
- This should not cause too much trouble for existing (stupid?)
- debuggers because they have to deal with empty upper bounds
- location descriptions anyway in order to be able to deal with
- incomplete array types.
-
- Of course an intelligent debugger (GDB?) should be able to
- comprehend that a missing upper bound specification in a
- array type used for a storage class `auto' local array variable
- indicates that the upper bound is both unknown (at compile-
- time) and unknowable (at run-time) due to optimization.
- */
+ /* Dynamic bounds may be represented by NOP_EXPR nodes containing
+ SAVE_EXPR nodes, in which case we can do something, or as
+ an expression, which we cannot represent. */
+ {
+ char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ sprintf (begin_label, BOUND_BEGIN_LABEL_FMT,
+ current_dienum, dim_num, u_or_l);
+
+ sprintf (end_label, BOUND_END_LABEL_FMT,
+ current_dienum, dim_num, u_or_l);
+
+ ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label);
+ ASM_OUTPUT_LABEL (asm_out_file, begin_label);
+
+ /* If optimization is turned on, the SAVE_EXPRs that describe
+ how to access the upper bound values are essentially bogus.
+ They only describe (at best) how to get at these values at
+ the points in the generated code right after they have just
+ been computed. Worse yet, in the typical case, the upper
+ bound values will not even *be* computed in the optimized
+ code, so these SAVE_EXPRs are entirely bogus.
+
+ In order to compensate for this fact, we check here to see
+ if optimization is enabled, and if so, we effectively create
+ an empty location description for the (unknown and unknowable)
+ upper bound.
+
+ This should not cause too much trouble for existing (stupid?)
+ debuggers because they have to deal with empty upper bounds
+ location descriptions anyway in order to be able to deal with
+ incomplete array types.
+
+ Of course an intelligent debugger (GDB?) should be able to
+ comprehend that a missing upper bound specification in a
+ array type used for a storage class `auto' local array variable
+ indicates that the upper bound is both unknown (at compile-
+ time) and unknowable (at run-time) due to optimization. */
+
+ if (! optimize)
+ {
+ while (TREE_CODE (bound) == NOP_EXPR
+ || TREE_CODE (bound) == CONVERT_EXPR)
+ bound = TREE_OPERAND (bound, 0);
- if (! optimize)
- output_loc_descriptor
- (eliminate_regs (SAVE_EXPR_RTL (bound), 0, NULL_RTX));
+ if (TREE_CODE (bound) == SAVE_EXPR)
+ output_loc_descriptor
+ (eliminate_regs (SAVE_EXPR_RTL (bound), 0, NULL_RTX, 0));
+ }
- ASM_OUTPUT_LABEL (asm_out_file, end_label);
- }
- break;
+ ASM_OUTPUT_LABEL (asm_out_file, end_label);
+ }
+ break;
- default:
- abort ();
}
}
/* Given an unsigned value, round it up to the lowest multiple of `boundary'
which is not less than the value itself. */
-inline unsigned
+static inline unsigned
ceiling (value, boundary)
register unsigned value;
register unsigned boundary;
pointer to the declared type for the relevant field variable, or return
`integer_type_node' if the given node turns out to be an ERROR_MARK node. */
-inline tree
+static inline tree
field_type (decl)
register tree decl;
{
node, return the alignment in bits for the type, or else return
BITS_PER_WORD if the node actually turns out to be an ERROR_MARK node. */
-inline unsigned
+static inline unsigned
simple_type_align_in_bits (type)
register tree type;
{
constant, or else return BITS_PER_WORD if the type actually turns out
to be an ERROR_MARK node. */
-inline unsigned
+static inline unsigned
simple_type_size_in_bits (type)
register tree type;
{
/* Generate an AT_sibling attribute. */
-inline void
+static inline void
sibling_attribute ()
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
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
+ represents an object declaration, but not a definition. So saith
the PLSIG.
*/
if (! is_pseudo_reg (rtl)
&& (GET_CODE (rtl) != MEM || ! is_pseudo_reg (XEXP (rtl, 0))))
- output_loc_descriptor (eliminate_regs (rtl, 0, NULL_RTX));
+ output_loc_descriptor (eliminate_regs (rtl, 0, NULL_RTX, 0));
ASM_OUTPUT_LABEL (asm_out_file, end_label);
}
object" which will be given in the AT_byte_size attribute for this
bit-field. (See the `byte_size_attribute' function below.) It is
also used when calculating the value of the AT_bit_offset attribute.
- (See the `bit_offset_attribute' function below.)
-*/
+ (See the `bit_offset_attribute' function below.) */
static void
-data_member_location_attribute (decl)
- register tree decl;
+data_member_location_attribute (t)
+ register tree t;
{
- register unsigned object_offset_in_bytes = field_byte_offset (decl);
+ register unsigned object_offset_in_bytes;
char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ if (TREE_CODE (t) == TREE_VEC)
+ object_offset_in_bytes = TREE_INT_CST_LOW (BINFO_OFFSET (t));
+ else
+ object_offset_in_bytes = field_byte_offset (t);
+
ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_location);
sprintf (begin_label, LOC_BEGIN_LABEL_FMT, current_dienum);
sprintf (end_label, LOC_END_LABEL_FMT, current_dienum);
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 (rtl == NULL)
+ 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));
+
+ /* Note that DECL_INCOMING_RTL may be NULL in here, but we handle
+ *all* cases where (rtl == NULL_RTX) just below. */
+
+ if (declared_type == passed_type)
+ rtl = DECL_INCOMING_RTL (decl);
+ else if (! BYTES_BIG_ENDIAN)
+ if (TREE_CODE (declared_type) == INTEGER_TYPE)
+ if (TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type))
+ rtl = DECL_INCOMING_RTL (decl);
+ }
+
+ if (rtl == NULL_RTX)
return;
switch (GET_CODE (rtl))
location_attribute (rtl);
break;
+ case CONCAT:
+ /* ??? CONCAT is used for complex variables, which may have the real
+ part stored in one place and the imag part stored somewhere else.
+ DWARF1 has no way to describe a variable that lives in two different
+ places, so we just describe where the first part lives, and hope that
+ the second part is stored after it. */
+ location_attribute (XEXP (rtl, 0));
+ break;
+
default:
abort (); /* Should never happen. */
}
/* Generate an AT_name attribute given some string value to be included as
the value of the attribute. */
-inline void
+static inline void
name_attribute (name_string)
register char *name_string;
{
}
}
-inline void
+static inline void
fund_type_attribute (ft_code)
register unsigned ft_code;
{
ASM_OUTPUT_LABEL (asm_out_file, end_label);
}
-inline void
+static inline void
user_def_type_attribute (type)
register tree type;
{
}
#ifdef USE_ORDERING_ATTRIBUTE
-inline void
+static inline void
ordering_attribute (ordering)
register unsigned ordering;
{
if (! type_is_fundamental (domain))
abort ();
- /* Output the representation format byte for this dimension. */
+ /* Output the representation format byte for this dimension. */
ASM_OUTPUT_DWARF_FMT_BYTE (asm_out_file,
FMT_CODE (1,
}
}
- /* Output the prefix byte that says that the element type is comming up. */
+ /* Output the prefix byte that says that the element type is coming up. */
ASM_OUTPUT_DWARF_FMT_BYTE (asm_out_file, FMT_ET);
Note that it is the size (in bytes) of the hypothetical "containing
object" which will be given in the AT_byte_size attribute for this
- bit-field. (See `byte_size_attribute' above.)
-*/
+ bit-field. (See `byte_size_attribute' above.) */
-inline void
+static inline void
bit_offset_attribute (decl)
register tree decl;
{
highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
highest_order_field_bit_offset = bitpos_int;
-#if (BYTES_BIG_ENDIAN == 0)
- highest_order_field_bit_offset
- += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl));
+ if (! BYTES_BIG_ENDIAN)
+ {
+ highest_order_field_bit_offset
+ += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl));
- highest_order_object_bit_offset += simple_type_size_in_bits (type);
-#endif /* (BYTES_BIG_ENDIAN == 0) */
+ highest_order_object_bit_offset += simple_type_size_in_bits (type);
+ }
bit_offset =
-#if (BYTES_BIG_ENDIAN == 0)
- highest_order_object_bit_offset - highest_order_field_bit_offset;
-#else /* (BYTES_BIG_ENDIAN != 0) */
- highest_order_field_bit_offset - highest_order_object_bit_offset;
-#endif /* (BYTES_BIG_ENDIAN != 0) */
+ (! BYTES_BIG_ENDIAN
+ ? highest_order_object_bit_offset - highest_order_field_bit_offset
+ : highest_order_field_bit_offset - highest_order_object_bit_offset);
ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_bit_offset);
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, bit_offset);
/* For a FIELD_DECL node which represents a bit field, output an attribute
which specifies the length in bits of the given field. */
-inline void
+static inline void
bit_size_attribute (decl)
register tree decl;
{
all of the enumeration constants associated with the given enumeration
type. */
-inline void
+static inline void
element_list_attribute (element)
register tree element;
{
/* Generate an AT_stmt_list attribute. These are normally present only in
DIEs with a TAG_compile_unit tag. */
-inline void
+static inline void
stmt_list_attribute (label)
register char *label;
{
/* Generate an AT_low_pc attribute for a label DIE, a lexical_block DIE or
for a subroutine DIE. */
-inline void
+static inline void
low_pc_attribute (asm_low_label)
register char *asm_low_label;
{
/* Generate an AT_high_pc attribute for a lexical_block DIE or for a
subroutine DIE. */
-inline void
+static inline void
high_pc_attribute (asm_high_label)
register char *asm_high_label;
{
/* Generate an AT_body_begin attribute for a subroutine DIE. */
-inline void
+static inline void
body_begin_attribute (asm_begin_label)
register char *asm_begin_label;
{
/* Generate an AT_body_end attribute for a subroutine DIE. */
-inline void
+static inline void
body_end_attribute (asm_end_label)
register char *asm_end_label;
{
/* Generate an AT_language attribute given a LANG value. These attributes
are used only within TAG_compile_unit DIEs. */
-inline void
+static inline void
language_attribute (language_code)
register unsigned language_code;
{
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, language_code);
}
-inline void
+static inline void
member_attribute (context)
register tree context;
{
}
}
-inline void
+static inline void
string_length_attribute (upper_bound)
register tree upper_bound;
{
ASM_OUTPUT_LABEL (asm_out_file, end_label);
}
-inline void
+static inline void
comp_dir_attribute (dirname)
register char *dirname;
{
ASM_OUTPUT_DWARF_STRING (asm_out_file, dirname);
}
-inline void
+static inline void
sf_names_attribute (sf_names_start_label)
register char *sf_names_start_label;
{
ASM_OUTPUT_DWARF_ADDR (asm_out_file, sf_names_start_label);
}
-inline void
+static inline void
src_info_attribute (src_info_start_label)
register char *src_info_start_label;
{
ASM_OUTPUT_DWARF_ADDR (asm_out_file, src_info_start_label);
}
-inline void
+static inline void
mac_info_attribute (mac_info_start_label)
register char *mac_info_start_label;
{
ASM_OUTPUT_DWARF_ADDR (asm_out_file, mac_info_start_label);
}
-inline void
+static inline void
prototyped_attribute (func_type)
register tree func_type;
{
}
}
-inline void
+static inline void
producer_attribute (producer)
register char *producer;
{
ASM_OUTPUT_DWARF_STRING (asm_out_file, producer);
}
-inline void
+static inline void
inline_attribute (decl)
register tree decl;
{
}
}
-inline void
+static inline void
containing_type_attribute (containing_type)
register tree containing_type;
{
ASM_OUTPUT_DWARF_REF (asm_out_file, label);
}
-inline void
+static inline void
abstract_origin_attribute (origin)
register tree origin;
{
}
#ifdef DWARF_DECL_COORDINATES
-inline void
+static inline void
src_coords_attribute (src_fileno, src_lineno)
register unsigned src_fileno;
register unsigned src_lineno;
}
#endif /* defined(DWARF_DECL_COORDINATES) */
-inline void
+static inline void
pure_or_virtual_attribute (func_decl)
register tree func_decl;
{
register enum tree_code code = TREE_CODE (type);
register int root_type_modified;
- if (TREE_CODE (type) == ERROR_MARK)
+ if (code == ERROR_MARK)
return;
/* Handle a special case. For functions whose return type is void,
we generate *no* type attribute. (Note that no object may have
type `void', so this only applies to function return types. */
- if (TREE_CODE (type) == VOID_TYPE)
+ if (code == VOID_TYPE)
return;
+ /* If this is a subtype, find the underlying type. Eventually,
+ this should write out the appropriate subtype info. */
+ while ((code == INTEGER_TYPE || code == REAL_TYPE)
+ && TREE_TYPE (type) != 0)
+ type = TREE_TYPE (type), code = TREE_CODE (type);
+
root_type_modified = (code == POINTER_TYPE || code == REFERENCE_TYPE
|| decl_const || decl_volatile
|| TYPE_READONLY (type) || TYPE_VOLATILE (type));
if (root_type_modified)
mod_u_d_type_attribute (type, decl_const, decl_volatile);
else
- /* We have to get the TYPE_MAIN_VARIANT here (and pass that to the
+ /* 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)
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));
+ user_def_type_attribute (type_main_variant (type));
}
/* Given a tree pointer to a struct, class, union, or enum type node, return
/* Find the IDENTIFIER_NODE for the type name. */
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
t = TYPE_NAME (type);
-#if 0
- /* The g++ front end makes the TYPE_NAME of *each* tagged type point
- to a TYPE_DECL node, regardless of whether or not a `typedef' was
- involved. This is distinctly different from what the gcc front-end
- does. It always makes the TYPE_NAME for each tagged type be either
- NULL (signifying an anonymous tagged type) or else a pointer to an
- IDENTIFIER_NODE. Obviously, we would like to generate correct Dwarf
- for both C and C++, but given this inconsistency in the TREE
- representation of tagged types for C and C++ in the GNU front-ends,
- we cannot support both languages correctly unless we introduce some
- front-end specific code here, and rms objects to that, so we can
- only generate correct Dwarf for one of these two languages. C is
- more important, so for now we'll do the right thing for C and let
- g++ go fish. */
- else
- if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)
+ /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
+ a TYPE_DECL node, regardless of whether or not a `typedef' was
+ involved. */
+ else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && ! DECL_IGNORED_P (TYPE_NAME (type)))
t = DECL_NAME (TYPE_NAME (type));
-#endif
+
/* Now get the name as a string, or invent one. */
if (t != 0)
name = IDENTIFIER_POINTER (t);
return (name == 0 || *name == '\0') ? 0 : name;
}
-inline void
+static inline void
dienum_push ()
{
/* Start by checking if the pending_sibling_stack needs to be expanded.
/* Pop the sibling stack so that the most recently pushed DIEnum becomes the
NEXT_DIE_NUM. */
-inline void
+static inline void
dienum_pop ()
{
pending_siblings--;
}
-inline tree
+static inline tree
member_declared_type (member)
register tree member;
{
: TREE_TYPE (member);
}
+/* Get the function's label, as described by its RTL.
+ This may be different from the DECL_NAME name used
+ in the source file. */
+
+static char *
+function_start_label (decl)
+ register tree decl;
+{
+ rtx x;
+ char *fnname;
+
+ x = DECL_RTL (decl);
+ if (GET_CODE (x) != MEM)
+ abort ();
+ x = XEXP (x, 0);
+ if (GET_CODE (x) != SYMBOL_REF)
+ abort ();
+ fnname = XSTR (x, 0);
+ return fnname;
+}
+
+
/******************************* DIEs ************************************/
/* Output routines for individual types of DIEs. */
#if 0
/* Implement this when there is a GNU FORTRAN or GNU Ada front end. */
+
static void
output_entry_point_die (arg)
register void *arg;
if (DECL_ABSTRACT (decl))
equate_decl_number_to_die_number (decl);
else
- low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ low_pc_attribute (function_start_label (decl));
}
#endif
equate_decl_number_to_die_number (decl);
else
{
- if (! DECL_EXTERNAL (decl))
+ if (! DECL_EXTERNAL (decl) && ! in_class
+ && decl == current_function_decl)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ low_pc_attribute (function_start_label (decl));
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);
+ if (use_gnu_debug_info_extensions)
+ {
+ 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);
+ }
}
}
}
equate_decl_number_to_die_number (decl);
else
{
- if (!DECL_EXTERNAL (decl))
+ if (! DECL_EXTERNAL (decl) && ! in_class
+ && current_function_decl == decl_function_context (decl))
location_or_const_value_attribute (decl);
}
}
member_attribute (DECL_CONTEXT (decl));
type_attribute (member_declared_type (decl),
TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
- if (DECL_BIT_FIELD_TYPE (decl)) /* If this is a bit field... */
+ if (DECL_BIT_FIELD_TYPE (decl)) /* If this is a bit field... */
{
byte_size_attribute (decl);
bit_size_attribute (decl);
/* Don't generate either pointer_type DIEs or reference_type DIEs. Use
modified types instead.
- We keep this code here just in case these types of DIEs may be needed
- to represent certain things in other languages (e.g. Pascal) someday.
-*/
+ We keep this code here just in case these types of DIEs may be
+ needed to represent certain things in other languages (e.g. Pascal)
+ someday. */
static void
output_pointer_type_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 (strcmp (language_string, "GNU F77") == 0)
+ language_attribute (LANG_FORTRAN77);
else if (flag_traditional)
language_attribute (LANG_C);
else
comp_dir_attribute (wd);
}
- if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ if (debug_info_level >= DINFO_LEVEL_NORMAL && use_gnu_debug_info_extensions)
{
sf_names_attribute (SFNAMES_BEGIN_LABEL);
src_info_attribute (SRCINFO_BEGIN_LABEL);
}
static void
+output_inheritance_die (arg)
+ register void *arg;
+{
+ register tree binfo = arg;
+
+ ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_inheritance);
+ sibling_attribute ();
+ type_attribute (BINFO_TYPE (binfo), 0, 0);
+ data_member_location_attribute (binfo);
+ if (TREE_VIA_VIRTUAL (binfo))
+ {
+ ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_virtual);
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
+ }
+ if (TREE_VIA_PUBLIC (binfo))
+ {
+ ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_public);
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
+ }
+ else if (TREE_VIA_PROTECTED (binfo))
+ {
+ ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_protected);
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
+ }
+}
+
+static void
output_structure_type_die (arg)
register void *arg;
{
if (TREE_ASM_WRITTEN (decl))
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
-
- low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ low_pc_attribute (function_start_label (decl));
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);
+ if (use_gnu_debug_info_extensions)
+ {
+ 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);
+ }
}
}
}
parameters as specified in some function type specification (except
for those which appear as part of a function *definition*).
- Note that we must be careful here to output all of the parameter DIEs
- *before* we output any DIEs needed to represent the types of the formal
- parameters. This keeps svr4 SDB happy because it (incorrectly) thinks
- that the first non-parameter DIE it sees ends the formal parameter list.
-*/
+ Note that we must be careful here to output all of the parameter
+ DIEs *before* we output any DIEs needed to represent the types of
+ the formal parameters. This keeps svr4 SDB happy because it
+ (incorrectly) thinks that the first non-parameter DIE it sees ends
+ the formal parameter list. */
static void
output_formal_types (function_or_method_type)
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.
-*/
+ true scope of the types we temporarily pended. */
-inline int
+static inline int
type_ok_for_scope (type, scope)
register tree type;
register tree scope;
(for C and C++ anyway) will be array types and function types. */
return is_tagged_type (type)
- ? (TYPE_CONTEXT (type) == scope)
+ ? (TYPE_CONTEXT (type) == scope
+ || (scope == NULL_TREE && is_tagged_type (TYPE_CONTEXT (type))
+ && TREE_ASM_WRITTEN (TYPE_CONTEXT (type))))
: (scope == NULL_TREE || ! is_tagged_type (scope));
}
Note that we have to process the list in beginning-to-end order,
because the call made here to output_type may cause yet more types
to be added to the end of the list, and we may have to output some
- of them too.
-*/
+ of them too. */
static void
output_pending_types_for_scope (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;
+ /* If this is a nested type whose containing class hasn't been
+ written out yet, writing it out will cover this one, too. */
+
+ if (TYPE_CONTEXT (type)
+ && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
+ && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+ {
+ output_type (TYPE_CONTEXT (type), containing_scope);
+ return;
+ }
+
/* Don't generate any DIEs for this type now unless it is OK to do so
(based upon what `type_ok_for_scope' tells us). */
case POINTER_TYPE:
case REFERENCE_TYPE:
+ /* Prevent infinite recursion in cases where this is a recursive
+ type. Recursive types are possible in Ada. */
+ TREE_ASM_WRITTEN (type) = 1;
/* For these types, all that is required is that we output a DIE
(or a set of DIEs) to represent the "basis" type. */
output_type (TREE_TYPE (type), containing_scope);
break;
case SET_TYPE:
- output_type (TREE_TYPE (type), containing_scope);
+ output_type (TYPE_DOMAIN (type), containing_scope);
output_die (output_set_type_die, type);
break;
abort (); /* No way to represent these in Dwarf yet! */
break;
- case STRING_TYPE:
- output_type (TREE_TYPE (type), containing_scope);
- output_die (output_string_type_die, type);
- break;
-
case FUNCTION_TYPE:
/* Force out return type (in case it wasn't forced out already). */
output_type (TREE_TYPE (type), containing_scope);
end_sibling_chain ();
break;
- case ARRAY_TYPE:
- {
- register tree element_type;
+ case ARRAY_TYPE:
+ if (TYPE_STRING_FLAG (type) && TREE_CODE(TREE_TYPE(type)) == CHAR_TYPE)
+ {
+ output_type (TREE_TYPE (type), containing_scope);
+ output_die (output_string_type_die, type);
+ }
+ else
+ {
+ register tree element_type;
- element_type = TREE_TYPE (type);
- while (TREE_CODE (element_type) == ARRAY_TYPE)
- element_type = TREE_TYPE (element_type);
+ element_type = TREE_TYPE (type);
+ while (TREE_CODE (element_type) == ARRAY_TYPE)
+ element_type = TREE_TYPE (element_type);
- output_type (element_type, containing_scope);
- output_die (output_array_type_die, type);
- }
+ output_type (element_type, containing_scope);
+ output_die (output_array_type_die, type);
+ }
break;
case ENUMERAL_TYPE:
time, we will certainly know as much about each file-scope tagged
type as we are ever going to know, so at that point in time, we
can safely generate correct Dwarf descriptions for these file-
- scope tagged types.
- */
+ scope tagged types. */
- if (TYPE_SIZE (type) == 0 && TYPE_CONTEXT (type) == NULL && !finalizing)
+ if (TYPE_SIZE (type) == 0
+ && (TYPE_CONTEXT (type) == NULL
+ || TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't')
+ && !finalizing)
return; /* EARLY EXIT! Avoid setting TREE_ASM_WRITTEN. */
/* Prevent infinite recursion in cases where the type of some
if (TYPE_SIZE (type))
{
+ /* First output info about the base classes. */
+ if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
+ {
+ register tree bases = TYPE_BINFO_BASETYPES (type);
+ register int n_bases = TREE_VEC_LENGTH (bases);
+ register int i;
+
+ for (i = 0; i < n_bases; i++)
+ output_die (output_inheritance_die, TREE_VEC_ELT (bases, i));
+ }
+
+ ++in_class;
+
{
register tree normal_member;
- /* First output info about the data members and type members. */
+ /* Now output info about the data members and type members. */
for (normal_member = TYPE_FIELDS (type);
normal_member;
}
{
- register tree vec_base;
+ register tree func_member;
/* Now output info about the function members (if any). */
- vec_base = TYPE_METHODS (type);
- if (vec_base)
- {
- register tree first_func_member = TREE_VEC_ELT (vec_base, 0);
- register tree func_member;
-
- /* This isn't documented, but the first element of the
- vector of member functions can be NULL in cases where
- the class type in question didn't have either a
- constructor or a destructor declared for it. We have
- to make allowances for that here. */
-
- if (first_func_member == NULL)
- first_func_member = TREE_VEC_ELT (vec_base, 1);
-
- for (func_member = first_func_member;
- func_member;
- func_member = TREE_CHAIN (func_member))
- output_decl (func_member, type);
- }
+ for (func_member = TYPE_METHODS (type);
+ func_member;
+ func_member = TREE_CHAIN (func_member))
+ output_decl (func_member, type);
}
+ --in_class;
+
/* 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. */
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));
the things which are local to the given block. */
static void
-output_block (stmt)
+output_block (stmt, depth)
register tree stmt;
+ int depth;
{
register int must_output_die = 0;
register tree origin;
not represent a "body block inlining" before trying to set the
`must_output_die' flag. */
- if (origin == NULL || ! is_body_block (origin))
+ if (! is_body_block (origin ? origin : stmt))
{
/* Determine if this block directly contains any "significant"
local declarations which we will need to output DIEs for. */
a "significant" local declaration gets restricted to include only
inlined function instances and local (nested) function definitions. */
- if (must_output_die)
+ if (origin_code == FUNCTION_DECL && BLOCK_ABSTRACT (stmt))
+ /* We don't care about an abstract inlined subroutine. */;
+ else if (must_output_die)
{
output_die ((origin_code == FUNCTION_DECL)
? output_inlined_subroutine_die
: output_lexical_block_die,
stmt);
- output_decls_for_scope (stmt);
+ output_decls_for_scope (stmt, depth);
end_sibling_chain ();
}
else
- output_decls_for_scope (stmt);
+ output_decls_for_scope (stmt, depth);
}
/* Output all of the decls declared within a given scope (also called
a `binding contour') and (recursively) all of it's sub-blocks. */
static void
-output_decls_for_scope (stmt)
+output_decls_for_scope (stmt, depth)
register tree stmt;
+ int depth;
{
/* Ignore blocks never really used to make RTL. */
if (! stmt || ! TREE_USED (stmt))
return;
- if (! BLOCK_ABSTRACT (stmt))
+ if (! BLOCK_ABSTRACT (stmt) && depth > 0)
next_block_number++;
/* Output the DIEs to represent all of the data objects, functions,
for (subblocks = BLOCK_SUBBLOCKS (stmt);
subblocks;
subblocks = BLOCK_CHAIN (subblocks))
- output_block (subblocks);
+ output_block (subblocks, depth + 1);
}
}
+/* Is this a typedef we can avoid emitting? */
+
+inline int
+is_redundant_typedef (decl)
+ register tree decl;
+{
+ if (TYPE_DECL_IS_STUB (decl))
+ return 1;
+ if (DECL_ARTIFICIAL (decl)
+ && DECL_CONTEXT (decl)
+ && is_tagged_type (DECL_CONTEXT (decl))
+ && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
+ && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
+ /* Also ignore the artificial member typedef for the class name. */
+ return 1;
+ return 0;
+}
+
/* Output Dwarf .debug information for a decl described by DECL. */
static void
if (TREE_CODE (decl) == ERROR_MARK)
return;
+ /* If a structure is declared within an initialization, e.g. as the
+ operand of a sizeof, then it will not have a name. We don't want
+ to output a DIE for it, as the tree nodes are in the temporary obstack */
+
+ if ((TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE)
+ && ((DECL_NAME (decl) == 0 && TYPE_NAME (TREE_TYPE (decl)) == 0)
+ || (TYPE_FIELDS (TREE_TYPE (decl))
+ && (TREE_CODE (TYPE_FIELDS (TREE_TYPE (decl))) == ERROR_MARK))))
+ return;
+
/* If this ..._DECL node is marked to be ignored, then ignore it.
But don't ignore a function definition, since that would screw
up our count of blocks, and that it turn will completely screw up the
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
output_type (TREE_TYPE (TREE_TYPE (decl)), containing_scope);
+ {
+ /* And its containing type. */
+ register tree origin = decl_class_context (decl);
+ if (origin)
+ output_type (origin, containing_scope);
+ }
+
/* If the following DIE will represent a function definition for a
function with "extern" linkage, output a special "pubnames" DIE
label just ahead of the actual DIE. A reference to this label
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 != current_function_decl || in_class)
output_formal_types (TREE_TYPE (decl));
else
{
- register tree arg_decls = DECL_ARGUMENTS (decl);
+ /* Generate DIEs to represent all known formal parameters */
- {
- register tree last_arg;
+ register tree arg_decls = DECL_ARGUMENTS (decl);
+ register tree parm;
+
+ /* WARNING! Kludge zone ahead! Here we have a special
+ hack for svr4 SDB compatibility. Instead of passing the
+ current FUNCTION_DECL node as the second parameter (i.e.
+ the `containing_scope' parameter) to `output_decl' (as
+ we ought to) we instead pass a pointer to our own private
+ fake_containing_scope node. That node is a RECORD_TYPE
+ node which NO OTHER TYPE may ever actually be a member of.
+
+ This pointer will ultimately get passed into `output_type'
+ as its `containing_scope' parameter. `Output_type' will
+ then perform its part in the hack... i.e. it will pend
+ the type of the formal parameter onto the pending_types
+ list. Later on, when we are done generating the whole
+ sequence of formal parameter DIEs for this function
+ definition, we will un-pend all previously pended types
+ of formal parameters for this function definition.
+
+ This whole kludge prevents any type DIEs from being
+ mixed in with the formal parameter DIEs. That's good
+ because svr4 SDB believes that the list of formal
+ parameter DIEs for a function ends wherever the first
+ non-formal-parameter DIE appears. Thus, we have to
+ keep the formal parameter DIEs segregated. They must
+ all appear (consecutively) at the start of the list of
+ children for the DIE representing the function definition.
+ Then (and only then) may we output any additional DIEs
+ needed to represent the types of these formal parameters.
+ */
- last_arg = (arg_decls && TREE_CODE (arg_decls) != ERROR_MARK)
- ? tree_last (arg_decls)
- : NULL;
+ /*
+ When generating DIEs, generate the unspecified_parameters
+ DIE instead if we come across the arg "__builtin_va_alist"
+ */
- /* Generate DIEs to represent all known formal parameters, but
- don't do it if this looks like a varargs function. A given
- function is considered to be a varargs function if (and only
- if) its last named argument is named `__builtin_va_alist'. */
+ for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
+ if (TREE_CODE (parm) == PARM_DECL)
+ {
+ if (DECL_NAME(parm) &&
+ !strcmp(IDENTIFIER_POINTER(DECL_NAME(parm)),
+ "__builtin_va_alist") )
+ output_die (output_unspecified_parameters_die, decl);
+ else
+ output_decl (parm, fake_containing_scope);
+ }
- if (! last_arg
- || ! DECL_NAME (last_arg)
- || strcmp (IDENTIFIER_POINTER (DECL_NAME (last_arg)),
- "__builtin_va_alist"))
- {
- register tree parm;
-
- /* WARNING! Kludge zone ahead! Here we have a special
- hack for svr4 SDB compatibility. Instead of passing the
- current FUNCTION_DECL node as the second parameter (i.e.
- the `containing_scope' parameter) to `output_decl' (as
- we ought to) we instead pass a pointer to our own private
- fake_containing_scope node. That node is a RECORD_TYPE
- node which NO OTHER TYPE may ever actually be a member of.
-
- This pointer will ultimately get passed into `output_type'
- as its `containing_scope' parameter. `Output_type' will
- then perform its part in the hack... i.e. it will pend
- the type of the formal parameter onto the pending_types
- list. Later on, when we are done generating the whole
- sequence of formal parameter DIEs for this function
- definition, we will un-pend all previously pended types
- of formal parameters for this function definition.
-
- This whole kludge prevents any type DIEs from being
- mixed in with the formal parameter DIEs. That's good
- because svr4 SDB believes that the list of formal
- parameter DIEs for a function ends wherever the first
- non-formal-parameter DIE appears. Thus, we have to
- keep the formal parameter DIEs segregated. They must
- all appear (consecutively) at the start of the list of
- children for the DIE representing the function definition.
- Then (and only then) may we output any additional DIEs
- needed to represent the types of these formal parameters.
- */
-
- for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
- if (TREE_CODE (parm) == PARM_DECL)
- output_decl (parm, fake_containing_scope);
-
- /* Now that we have finished generating all of the DIEs to
- represent the formal parameters themselves, force out
- any DIEs needed to represent their types. We do this
- simply by un-pending all previously pended types which
- can legitimately go into the chain of children DIEs for
- the current FUNCTION_DECL. */
+ /*
+ Now that we have finished generating all of the DIEs to
+ represent the formal parameters themselves, force out
+ any DIEs needed to represent their types. We do this
+ simply by un-pending all previously pended types which
+ can legitimately go into the chain of children DIEs for
+ the current FUNCTION_DECL.
+ */
- output_pending_types_for_scope (decl);
- }
- }
+ output_pending_types_for_scope (decl);
- /* Now try to decide if we should put an ellipsis at the end. */
+ /*
+ Decide whether we need a unspecified_parameters DIE at the end.
+ There are 2 more cases to do this for:
+ 1) the ansi ... declaration - this is detectable when the end
+ of the arg list is not a void_type_node
+ 2) an unprototyped function declaration (not a definition). This
+ just means that we have no info about the parameters at all.
+ */
{
- register int has_ellipsis = TRUE; /* default assumption */
register tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
if (fn_arg_types)
{
- /* This function declaration/definition was prototyped. */
-
- /* If the list of formal argument types ends with a
- void_type_node, then the formals list did *not* end
- with an ellipsis. */
-
- if (TREE_VALUE (tree_last (fn_arg_types)) == void_type_node)
- has_ellipsis = FALSE;
- }
- else
- {
- /* This function declaration/definition was not prototyped. */
-
- /* Note that all non-prototyped function *declarations* are
- assumed to represent varargs functions (until proven
- otherwise). */
-
- if (DECL_INITIAL (decl)) /* if this is a func definition */
- {
- if (!arg_decls)
- has_ellipsis = FALSE; /* no args == (void) */
- else
- {
- /* For a non-prototyped function definition which
- declares one or more formal parameters, if the name
- of the first formal parameter is *not*
- __builtin_va_alist then we must assume that this
- is *not* a varargs function. */
-
- if (DECL_NAME (arg_decls)
- && strcmp (IDENTIFIER_POINTER (DECL_NAME (arg_decls)),
- "__builtin_va_alist"))
- has_ellipsis = FALSE;
- }
- }
- }
-
- if (has_ellipsis)
- output_die (output_unspecified_parameters_die, decl);
+ /* this is the prototyped case, check for ... */
+ if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
+ output_die (output_unspecified_parameters_die, decl);
+ }
+ else
+ {
+ /* this is unprototyped, check for undefined (just declaration) */
+ if (!DECL_INITIAL (decl))
+ output_die (output_unspecified_parameters_die, decl);
+ }
}
- }
-
- /* Output Dwarf info for all of the stuff within the body of the
- function (if it has one - it may be just a declaration). */
- {
- register tree outer_scope = DECL_INITIAL (decl);
+ /* Output Dwarf info for all of the stuff within the body of the
+ function (if it has one - it may be just a declaration). */
- if (outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
{
- /* Note that here, `outer_scope' is a pointer to the outermost
- BLOCK node created to represent a function.
- This outermost BLOCK actually represents the outermost
- binding contour for the function, i.e. the contour in which
- the function's formal parameters and labels get declared.
-
- Curiously, it appears that the front end doesn't actually
- put the PARM_DECL nodes for the current function onto the
- BLOCK_VARS list for this outer scope. (They are strung
- off of the DECL_ARGUMENTS list for the function instead.)
- The BLOCK_VARS list for the `outer_scope' does provide us
- with a list of the LABEL_DECL nodes for the function however,
- and we output DWARF info for those here.
-
- Just within the `outer_scope' there will be another BLOCK
- node representing the function's outermost pair of curly
- braces. We musn't generate a lexical_block DIE for this
- outermost pair of curly braces because that is not really an
- independent scope according to ANSI C rules. Rather, it is
- the same scope in which the parameters were declared. */
-
- {
- register tree label;
-
- for (label = BLOCK_VARS (outer_scope);
- label;
- label = TREE_CHAIN (label))
- output_decl (label, outer_scope);
- }
-
- /* Note here that `BLOCK_SUBBLOCKS (outer_scope)' points to a
- list of BLOCK nodes which is always only one element long.
- That one element represents the outermost pair of curley
- braces for the function body. */
-
- output_decls_for_scope (BLOCK_SUBBLOCKS (outer_scope));
+ register tree outer_scope = DECL_INITIAL (decl);
- /* Finally, force out any pending types which are local to the
- outermost block of this function definition. These will
- all have a TYPE_CONTEXT which points to the FUNCTION_DECL
- node itself. */
+ if (outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
+ {
+ /* Note that here, `outer_scope' is a pointer to the outermost
+ BLOCK node created to represent a function.
+ This outermost BLOCK actually represents the outermost
+ binding contour for the function, i.e. the contour in which
+ the function's formal parameters and labels get declared.
+
+ Curiously, it appears that the front end doesn't actually
+ put the PARM_DECL nodes for the current function onto the
+ BLOCK_VARS list for this outer scope. (They are strung
+ off of the DECL_ARGUMENTS list for the function instead.)
+ The BLOCK_VARS list for the `outer_scope' does provide us
+ with a list of the LABEL_DECL nodes for the function however,
+ and we output DWARF info for those here.
+
+ Just within the `outer_scope' there will be a BLOCK node
+ representing the function's outermost pair of curly braces,
+ and any blocks used for the base and member initializers of
+ a C++ constructor function. */
+
+ output_decls_for_scope (outer_scope, 0);
+
+ /* Finally, force out any pending types which are local to the
+ outermost block of this function definition. These will
+ all have a TYPE_CONTEXT which points to the FUNCTION_DECL
+ node itself. */
- output_pending_types_for_scope (decl);
+ output_pending_types_for_scope (decl);
+ }
}
- }
+ }
/* Generate a terminator for the list of stuff `owned' by this
function. */
a return type or a formal parameter type of some function. */
if (debug_info_level <= DINFO_LEVEL_TERSE)
- if (DECL_NAME (decl) != NULL
- || ! TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)))
+ if (! TYPE_DECL_IS_STUB (decl)
+ || (! TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)) && ! in_class))
return;
- /* In the special case of a null-named TYPE_DECL node (representing
- the declaration of some type tag), if the given TYPE_DECL is
+ /* In the special case of a TYPE_DECL node representing
+ the declaration of some type tag, if the given TYPE_DECL is
marked as having been instantiated from some other (original)
TYPE_DECL node (e.g. one which was generated within the original
definition of an inline function) we have to generate a special
(abbreviated) TAG_structure_type, TAG_union_type, or
TAG_enumeration-type DIE here. */
- if (! DECL_NAME (decl) && DECL_ABSTRACT_ORIGIN (decl))
+ if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl))
{
output_tagged_type_instantiation (TREE_TYPE (decl));
return;
output_type (TREE_TYPE (decl), containing_scope);
- /* Note that unlike the gcc front end (which generates a NULL named
- TYPE_DECL node for each complete tagged type, each array type,
- and each function type node created) the g++ front end generates
- a *named* TYPE_DECL node for each tagged type node created.
- Unfortunately, these g++ TYPE_DECL nodes cause us to output many
- superfluous and unnecessary TAG_typedef DIEs here. When g++ is
- fixed to stop generating these superfluous named TYPE_DECL nodes,
- the superfluous TAG_typedef DIEs will likewise cease. */
-
- if (DECL_NAME (decl))
+ if (! is_redundant_typedef (decl))
/* Output a DIE to represent the typedef itself. */
output_die (output_typedef_die, decl);
break;
output_type (TREE_TYPE (decl), containing_scope);
+ {
+ /* And its containing type. */
+ register tree origin = decl_class_context (decl);
+ if (origin)
+ output_type (origin, containing_scope);
+ }
+
/* If the following DIE will represent a data object definition for a
data object with "extern" linkage, output a special "pubnames" DIE
label just ahead of the actual DIE. A reference to this label
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 clairvoyant,
+ 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 functions, 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)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- text_section ();
+ function_section (current_function_decl);
sprintf (label, BLOCK_BEGIN_LABEL_FMT, blocknum);
ASM_OUTPUT_LABEL (asm_out_file, label);
}
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- text_section ();
+ function_section (current_function_decl);
sprintf (label, BLOCK_END_LABEL_FMT, blocknum);
ASM_OUTPUT_LABEL (asm_out_file, label);
}
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- text_section ();
+ function_section (current_function_decl);
sprintf (label, INSN_LABEL_FMT, current_funcdef_number,
(unsigned) INSN_UID (insn));
ASM_OUTPUT_LABEL (asm_out_file, label);
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- text_section ();
+ if (! use_gnu_debug_info_extensions)
+ return;
+ function_section (current_function_decl);
sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
ASM_OUTPUT_LABEL (asm_out_file, label);
}
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- text_section ();
+ if (! use_gnu_debug_info_extensions)
+ return;
+ function_section (current_function_decl);
sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
ASM_OUTPUT_LABEL (asm_out_file, label);
}
calculated, and where at least one of the two symbol references is a
forward reference. (This bug could be tickled by our .debug_srcinfo
entries if we don't output their corresponding .debug_sfnames entries
- before them.)
-*/
+ before them.) */
static unsigned
lookup_filename (file_name)
register char *filename;
register unsigned line;
{
- if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ if (debug_info_level >= DINFO_LEVEL_NORMAL
+ /* We can't emit line number info for functions in separate sections,
+ because the assembler can't subtract labels in different sections. */
+ && DECL_SECTION_NAME (current_function_decl) == NULL_TREE)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
static unsigned last_line_entry_num = 0;
static unsigned prev_file_entry_num = (unsigned) -1;
- register unsigned this_file_entry_num = lookup_filename (filename);
+ register unsigned this_file_entry_num;
- text_section ();
+ function_section (current_function_decl);
sprintf (label, LINE_CODE_LABEL_FMT, ++last_line_entry_num);
ASM_OUTPUT_LABEL (asm_out_file, label);
fputc ('\n', asm_out_file);
- ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION);
+ if (use_gnu_debug_info_extensions)
+ this_file_entry_num = lookup_filename (filename);
+ else
+ this_file_entry_num = (unsigned) -1;
+
+ ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION);
if (this_file_entry_num != prev_file_entry_num)
{
char line_entry_label[MAX_ARTIFICIAL_LABEL_BYTES];
register char *type_and_offset;
register char *string;
{
+ if (! use_gnu_debug_info_extensions)
+ return;
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, MACINFO_SECTION);
fprintf (asm_out_file, "\t%s\t%s\n", UNALIGNED_INT_ASM_OP, type_and_offset);
if (debug_info_level >= DINFO_LEVEL_NORMAL)
{
- /* Output a starting label and an initial (compilation directory)
- entry for the .debug_sfnames section. The starting label will be
- referenced by the initial entry in the .debug_srcinfo section. */
+ if (use_gnu_debug_info_extensions)
+ {
+ /* Output a starting label and an initial (compilation directory)
+ entry for the .debug_sfnames section. The starting label will be
+ referenced by the initial entry in the .debug_srcinfo section. */
- fputc ('\n', asm_out_file);
- ASM_OUTPUT_PUSH_SECTION (asm_out_file, SFNAMES_SECTION);
- ASM_OUTPUT_LABEL (asm_out_file, SFNAMES_BEGIN_LABEL);
- {
- register char *pwd = getpwd ();
- register unsigned len = strlen (pwd);
- register char *dirname = (char *) xmalloc (len + 2);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_PUSH_SECTION (asm_out_file, SFNAMES_SECTION);
+ ASM_OUTPUT_LABEL (asm_out_file, SFNAMES_BEGIN_LABEL);
+ {
+ register char *pwd;
+ register unsigned len;
+ register char *dirname;
+
+ pwd = getpwd ();
+ if (!pwd)
+ pfatal_with_name ("getpwd");
+ len = strlen (pwd);
+ dirname = (char *) xmalloc (len + 2);
- strcpy (dirname, pwd);
- strcpy (dirname + len, "/");
- ASM_OUTPUT_DWARF_STRING (asm_out_file, dirname);
- free (dirname);
- }
- ASM_OUTPUT_POP_SECTION (asm_out_file);
+ strcpy (dirname, pwd);
+ strcpy (dirname + len, "/");
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, dirname);
+ free (dirname);
+ }
+ ASM_OUTPUT_POP_SECTION (asm_out_file);
+ }
- if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE
+ && use_gnu_debug_info_extensions)
{
/* Output a starting label for the .debug_macinfo section. This
label will be referenced by the AT_mac_info attribute in the
ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
ASM_OUTPUT_POP_SECTION (asm_out_file);
- /* Generate the initial entry for the .debug_srcinfo section. */
-
- fputc ('\n', asm_out_file);
- ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
- ASM_OUTPUT_LABEL (asm_out_file, SRCINFO_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, LINE_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, SFNAMES_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_END_LABEL);
+ if (use_gnu_debug_info_extensions)
+ {
+ /* Generate the initial entry for the .debug_srcinfo section. */
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
+ ASM_OUTPUT_LABEL (asm_out_file, SRCINFO_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, LINE_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, SFNAMES_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_END_LABEL);
#ifdef DWARF_TIMESTAMPS
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file, time (NULL));
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, time (NULL));
#else
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
#endif
- ASM_OUTPUT_POP_SECTION (asm_out_file);
+ ASM_OUTPUT_POP_SECTION (asm_out_file);
+ }
/* Generate the initial entry for the .debug_pubnames section. */
(or blame). I didn't think of this scheme. I just conformed to it.
*/
- output_die (output_padded_null_die, (void *)0);
+ output_die (output_padded_null_die, (void *) 0);
dienum_pop ();
sprintf (label, DIE_BEGIN_LABEL_FMT, NEXT_DIE_NUM);
ASM_OUTPUT_LABEL (asm_out_file, LINE_END_LABEL);
ASM_OUTPUT_POP_SECTION (asm_out_file);
- /* Output a terminating entry for the .debug_srcinfo section. */
-
- fputc ('\n', asm_out_file);
- ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
- ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
- LINE_LAST_ENTRY_LABEL, LINE_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
- ASM_OUTPUT_POP_SECTION (asm_out_file);
+ if (use_gnu_debug_info_extensions)
+ {
+ /* Output a terminating entry for the .debug_srcinfo section. */
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
+ ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
+ LINE_LAST_ENTRY_LABEL, LINE_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
+ ASM_OUTPUT_POP_SECTION (asm_out_file);
+ }
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{