/* Output Dwarf2 format symbol table information from GCC.
Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004 Free Software Foundation, Inc.
+ 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Gary Funck (gary@intrepid.com).
Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
Extensively modified by Jason Merrill (jason@cygnus.com).
const char *dw_fde_begin;
const char *dw_fde_current_label;
const char *dw_fde_end;
+ const char *dw_fde_hot_section_label;
+ const char *dw_fde_hot_section_end_label;
+ const char *dw_fde_unlikely_section_label;
+ const char *dw_fde_unlikely_section_end_label;
+ bool dw_fde_switched_sections;
dw_cfi_ref dw_fde_cfi;
unsigned funcdef_number;
unsigned all_throwers_are_sibcalls : 1;
dw2_asm_output_encoded_addr_rtx (fde_encoding,
sym_ref,
"FDE initial location");
- dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
- fde->dw_fde_end, fde->dw_fde_begin,
- "FDE address range");
+ if (fde->dw_fde_switched_sections)
+ {
+ rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
+ fde->dw_fde_unlikely_section_label);
+ rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
+ fde->dw_fde_hot_section_label);
+ SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL;
+ SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL;
+ dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3,
+ "FDE initial location");
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_hot_section_end_label,
+ fde->dw_fde_hot_section_label,
+ "FDE address range");
+ dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2,
+ "FDE initial location");
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_unlikely_section_end_label,
+ fde->dw_fde_unlikely_section_label,
+ "FDE address range");
+ }
+ else
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_end, fde->dw_fde_begin,
+ "FDE address range");
}
else
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
"FDE initial location");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE,
- fde->dw_fde_end, fde->dw_fde_begin,
- "FDE address range");
+ if (fde->dw_fde_switched_sections)
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+ fde->dw_fde_hot_section_label,
+ "FDE initial location");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_hot_section_end_label,
+ fde->dw_fde_hot_section_label,
+ "FDE address range");
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+ fde->dw_fde_unlikely_section_label,
+ "FDE initial location");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_unlikely_section_end_label,
+ fde->dw_fde_unlikely_section_label,
+ "FDE address range");
+ }
+ else
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_end, fde->dw_fde_begin,
+ "FDE address range");
}
if (augmentation[0])
fde->decl = current_function_decl;
fde->dw_fde_begin = dup_label;
fde->dw_fde_current_label = NULL;
+ fde->dw_fde_hot_section_label = NULL;
+ fde->dw_fde_hot_section_end_label = NULL;
+ fde->dw_fde_unlikely_section_label = NULL;
+ fde->dw_fde_unlikely_section_end_label = NULL;
+ fde->dw_fde_switched_sections = false;
fde->dw_fde_end = NULL;
fde->dw_fde_cfi = NULL;
fde->funcdef_number = current_function_funcdef_no;
dwarf2out_frame_finish (void)
{
/* Output call frame information. */
- if (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+ if (write_symbols == DWARF2_DEBUG
+ || write_symbols == VMS_AND_DWARF2_DEBUG
+#ifdef DWARF2_FRAME_INFO
+ || DWARF2_FRAME_INFO
+#endif
+ )
output_call_frame_info (0);
#ifndef TARGET_UNWIND_INFO
static void dwarf2out_abstract_function (tree);
static void dwarf2out_var_location (rtx);
static void dwarf2out_begin_function (tree);
+static void dwarf2out_switch_text_section (void);
/* The debug hooks structure. */
dwarf2out_abstract_function, /* outlining_inline_function */
debug_nothing_rtx, /* label */
debug_nothing_int, /* handle_pch */
- dwarf2out_var_location
+ dwarf2out_var_location,
+ dwarf2out_switch_text_section,
+ 1 /* start_end_main_source_file */
};
#endif
\f
{
rtx GTY (()) var_loc_note;
const char * GTY (()) label;
+ const char * GTY (()) section_label;
struct var_loc_node * GTY (()) next;
};
static const char *dwarf_tag_name (unsigned);
static const char *dwarf_attr_name (unsigned);
static const char *dwarf_form_name (unsigned);
-#if 0
-static const char *dwarf_type_encoding_name (unsigned);
-#endif
static tree decl_ultimate_origin (tree);
static tree block_ultimate_origin (tree);
static tree decl_class_context (tree);
#endif
\f
/* We allow a language front-end to designate a function that is to be
- called to "demangle" any name before it it put into a DIE. */
+ called to "demangle" any name before it is put into a DIE. */
static const char *(*demangle_name_func) (const char *);
return "DW_FORM_<unknown>";
}
}
-
-/* Convert a DWARF type code into its string name. */
-
-#if 0
-static const char *
-dwarf_type_encoding_name (unsigned enc)
-{
- switch (enc)
- {
- case DW_ATE_address:
- return "DW_ATE_address";
- case DW_ATE_boolean:
- return "DW_ATE_boolean";
- case DW_ATE_complex_float:
- return "DW_ATE_complex_float";
- case DW_ATE_float:
- return "DW_ATE_float";
- case DW_ATE_signed:
- return "DW_ATE_signed";
- case DW_ATE_signed_char:
- return "DW_ATE_signed_char";
- case DW_ATE_unsigned:
- return "DW_ATE_unsigned";
- case DW_ATE_unsigned_char:
- return "DW_ATE_unsigned_char";
- default:
- return "DW_ATE_<unknown>";
- }
-}
-#endif
\f
/* Determine the "ultimate origin" of a decl. The decl may be an inlined
instance of an inlined instance of a decl which is local to an inline
*d = new_loc_list (descr, begin, end, section, 0);
}
+static void
+dwarf2out_switch_text_section (void)
+{
+ dw_fde_ref fde;
+
+ fde = &fde_table[fde_table_in_use - 1];
+ fde->dw_fde_switched_sections = true;
+ fde->dw_fde_hot_section_label = xstrdup (hot_section_label);
+ fde->dw_fde_hot_section_end_label = xstrdup (hot_section_end_label);
+ fde->dw_fde_unlikely_section_label = xstrdup (unlikely_section_label);
+ fde->dw_fde_unlikely_section_end_label = xstrdup (cold_section_end_label);
+ separate_line_info_table_in_use++;
+}
+
/* Output the location list given to us. */
static void
}
dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
- text_section_label, "Length");
+ if (last_text_section == in_unlikely_executed_text
+ || (last_text_section == in_named
+ && last_text_section_name == unlikely_text_section_name))
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
+ unlikely_section_label, "Length");
+ else
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
+ text_section_label, "Length");
for (i = 0; i < arange_table_in_use; i++)
{
base of the text section. */
if (separate_line_info_table_in_use == 0)
{
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
- text_section_label,
- fmt, i * 2 * DWARF2_ADDR_SIZE);
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
- text_section_label, NULL);
+ if (last_text_section == in_unlikely_executed_text
+ || (last_text_section == in_named
+ && last_text_section_name == unlikely_text_section_name))
+ {
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
+ unlikely_section_label,
+ fmt, i * 2 * DWARF2_ADDR_SIZE);
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
+ unlikely_section_label, NULL);
+ }
+ else
+ {
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
+ text_section_label,
+ fmt, i * 2 * DWARF2_ADDR_SIZE);
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
+ text_section_label, NULL);
+ }
}
/* Otherwise, we add a DW_AT_entry_pc attribute to force the
a series of state machine operations. */
current_file = 1;
current_line = 1;
- strcpy (prev_line_label, text_section_label);
+
+ if (last_text_section == in_unlikely_executed_text
+ || (last_text_section == in_named
+ && last_text_section_name == unlikely_text_section_name))
+ strcpy (prev_line_label, unlikely_section_label);
+ else
+ strcpy (prev_line_label, text_section_label);
for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
{
dw_line_info_ref line_info = &line_info_table[lt_index];
case METHOD_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
- case FILE_TYPE:
case OFFSET_TYPE:
case LANG_TYPE:
case VECTOR_TYPE:
concat_loc_descriptor (rtx x0, rtx x1)
{
dw_loc_descr_ref cc_loc_result = NULL;
- dw_loc_descr_ref x0_ref = loc_descriptor (x0, true);
- dw_loc_descr_ref x1_ref = loc_descriptor (x1, true);
+ dw_loc_descr_ref x0_ref = loc_descriptor (x0, false);
+ dw_loc_descr_ref x1_ref = loc_descriptor (x1, false);
if (x0_ref == 0 || x1_ref == 0)
return 0;
/* Certain constructs can only be represented at top-level. */
if (want_address == 2)
- return loc_descriptor (rtl, true);
+ return loc_descriptor (rtl, false);
mode = GET_MODE (rtl);
if (MEM_P (rtl))
rtl = XEXP (rtl, 0);
have_address = 1;
}
- ret = mem_loc_descriptor (rtl, mode, true);
+ ret = mem_loc_descriptor (rtl, mode, false);
}
}
break;
return 0;
mode = GET_MODE (rtl);
rtl = XEXP (rtl, 0);
- ret = mem_loc_descriptor (rtl, mode, true);
+ ret = mem_loc_descriptor (rtl, mode, false);
have_address = 1;
break;
}
}
+/* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
+ for use in a later add_const_value_attribute call. */
+
+static rtx
+rtl_for_decl_init (tree init, tree type)
+{
+ rtx rtl = NULL_RTX;
+
+ /* If a variable is initialized with a string constant without embedded
+ zeros, build CONST_STRING. */
+ if (TREE_CODE (init) == STRING_CST && TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree enttype = TREE_TYPE (type);
+ tree domain = TYPE_DOMAIN (type);
+ enum machine_mode mode = TYPE_MODE (enttype);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
+ && domain
+ && integer_zerop (TYPE_MIN_VALUE (domain))
+ && compare_tree_int (TYPE_MAX_VALUE (domain),
+ TREE_STRING_LENGTH (init) - 1) == 0
+ && ((size_t) TREE_STRING_LENGTH (init)
+ == strlen (TREE_STRING_POINTER (init)) + 1))
+ rtl = gen_rtx_CONST_STRING (VOIDmode,
+ ggc_strdup (TREE_STRING_POINTER (init)));
+ }
+ /* If the initializer is something that we know will expand into an
+ immediate RTL constant, expand it now. Expanding anything else
+ tends to produce unresolved symbols; see debug/5770 and c++/6381. */
+ /* Aggregate, vector, and complex types may contain constructors that may
+ result in code being generated when expand_expr is called, so we can't
+ handle them here. Integer and float are useful and safe types to handle
+ here. */
+ else if ((INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type))
+ && initializer_constant_valid_p (init, type) == null_pointer_node)
+ {
+ rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+
+ /* If expand_expr returns a MEM, it wasn't immediate. */
+ gcc_assert (!rtl || !MEM_P (rtl));
+ }
+
+ return rtl;
+}
+
+/* Generate RTL for the variable DECL to represent its location. */
+
static rtx
rtl_for_decl_location (tree decl)
{
and will have been substituted directly into all expressions that use it.
C does not have such a concept, but C++ and other languages do. */
else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
- {
- /* If a variable is initialized with a string constant without embedded
- zeros, build CONST_STRING. */
- if (TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
- && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
- {
- tree arrtype = TREE_TYPE (decl);
- tree enttype = TREE_TYPE (arrtype);
- tree domain = TYPE_DOMAIN (arrtype);
- tree init = DECL_INITIAL (decl);
- enum machine_mode mode = TYPE_MODE (enttype);
-
- if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
- && domain
- && integer_zerop (TYPE_MIN_VALUE (domain))
- && compare_tree_int (TYPE_MAX_VALUE (domain),
- TREE_STRING_LENGTH (init) - 1) == 0
- && ((size_t) TREE_STRING_LENGTH (init)
- == strlen (TREE_STRING_POINTER (init)) + 1))
- rtl = gen_rtx_CONST_STRING (VOIDmode,
- ggc_strdup (TREE_STRING_POINTER (init)));
- }
- /* If the initializer is something that we know will expand into an
- immediate RTL constant, expand it now. Expanding anything else
- tends to produce unresolved symbols; see debug/5770 and c++/6381. */
- else if (TREE_CODE (DECL_INITIAL (decl)) == INTEGER_CST
- || TREE_CODE (DECL_INITIAL (decl)) == REAL_CST)
- {
- rtl = expand_expr (DECL_INITIAL (decl), NULL_RTX, VOIDmode,
- EXPAND_INITIALIZER);
- /* If expand_expr returns a MEM, it wasn't immediate. */
- gcc_assert (!rtl || !MEM_P (rtl));
- }
- }
+ rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
if (rtl)
rtl = targetm.delegitimize_address (rtl);
return rtl;
}
+/* Return true if DECL's containing function has a frame base attribute.
+ Return false otherwise. */
+
+static bool
+containing_function_has_frame_base (tree decl)
+{
+ tree declcontext = decl_function_context (decl);
+ dw_die_ref context;
+ dw_attr_ref attr;
+
+ if (!declcontext)
+ return false;
+
+ context = lookup_decl_die (declcontext);
+ if (!context)
+ return false;
+
+ for (attr = context->die_attr; attr; attr = attr->dw_attr_next)
+ if (attr->dw_attr == DW_AT_frame_base)
+ return true;
+ return false;
+}
+
/* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
data attribute for a variable or a parameter. We generate the
DW_AT_const_value attribute only in those cases where the given variable
rtx rtl;
dw_loc_descr_ref descr;
var_loc_list *loc_list;
-
+ bool can_use_fb;
+ struct var_loc_node *node;
if (TREE_CODE (decl) == ERROR_MARK)
return;
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL);
+
+ can_use_fb = containing_function_has_frame_base (decl);
/* See if we possibly have multiple locations for this variable. */
loc_list = lookup_decl_loc (decl);
const char *endname;
dw_loc_list_ref list;
rtx varloc;
- struct var_loc_node *node;
+
/* We need to figure out what section we should use as the base
for the address ranges where a given location is valid.
tree sectree = DECL_SECTION_NAME (current_function_decl);
secname = TREE_STRING_POINTER (sectree);
}
+ else if (last_text_section == in_unlikely_executed_text
+ || (last_text_section == in_named
+ && last_text_section_name == unlikely_text_section_name))
+ secname = unlikely_section_label;
else
secname = text_section_label;
node = loc_list->first;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- list = new_loc_list (loc_descriptor (varloc, attr != DW_AT_frame_base),
+ list = new_loc_list (loc_descriptor (varloc, can_use_fb),
node->label, node->next->label, secname, 1);
node = node->next;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
add_loc_descr_to_loc_list (&list,
loc_descriptor (varloc,
- attr != DW_AT_frame_base),
+ can_use_fb),
node->label, node->next->label, secname);
}
}
add_loc_descr_to_loc_list (&list,
loc_descriptor (varloc,
- attr != DW_AT_frame_base),
+ can_use_fb),
node->label, endname, secname);
}
return;
}
+ /* Try to get some constant RTL for this decl, and use that as the value of
+ the location. */
+
rtl = rtl_for_decl_location (decl);
if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
{
add_const_value_attribute (die, rtl);
return;
}
-
+
+ /* We couldn't get any rtl, and we had no >1 element location list, so try
+ directly generating the location description from the tree. */
descr = loc_descriptor_from_tree (decl);
if (descr)
- add_AT_location_description (die, attr, descr);
+ {
+ add_AT_location_description (die, attr, descr);
+ return;
+ }
+
+ /* Lastly, if we have tried to generate the location otherwise, and it
+ didn't work out (we wouldn't be here if we did), and we have a one entry
+ location list, try generating a location from that. */
+ if (loc_list && loc_list->first)
+ {
+ node = loc_list->first;
+ descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note),
+ can_use_fb);
+ if (descr)
+ add_AT_location_description (die, attr, descr);
+ }
}
/* If we don't have a copy of this variable in memory for some reason (such
{
tree init = DECL_INITIAL (decl);
tree type = TREE_TYPE (decl);
+ rtx rtl;
- if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init
- && initializer_constant_valid_p (init, type) == null_pointer_node)
+ if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init)
/* OK */;
else
return;
- switch (TREE_CODE (type))
- {
- case INTEGER_TYPE:
- if (host_integerp (init, 0))
- add_AT_unsigned (var_die, DW_AT_const_value,
- tree_low_cst (init, 0));
- else
- add_AT_long_long (var_die, DW_AT_const_value,
- TREE_INT_CST_HIGH (init),
- TREE_INT_CST_LOW (init));
- break;
-
- default:;
- }
+ rtl = rtl_for_decl_init (init, type);
+ if (rtl)
+ add_const_value_attribute (var_die, rtl);
}
/* Generate a DW_AT_name attribute given some string value to be included as
if (TYPE_P (fn))
fn = TYPE_STUB_DECL (fn);
-
+
fn = decl_function_context (fn);
if (fn)
dwarf2out_abstract_function (fn);
else if (TYPE_P (origin))
origin_die = lookup_type_die (origin);
- gcc_assert (origin_die);
+ /* XXX: Functions that are never lowered don't always have correct block
+ trees (in the case of java, they simply have no block tree, in some other
+ languages). For these functions, there is nothing we can really do to
+ output correct debug info for inlined functions in all cases. Rather
+ than abort, we'll just produce deficient debug info now, in that we will
+ have variables without a proper abstract origin. In the future, when all
+ functions are lowered, we should re-add a gcc_assert (origin_die)
+ here. */
- add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
+ if (origin_die)
+ add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
}
/* We do not currently support the pure_virtual attribute. */
if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
&& ! lookup_decl_die (member))
{
+ dw_die_ref type_die;
gcc_assert (!decl_ultimate_origin (member));
push_decl_scope (type);
+ type_die = lookup_type_die (type);
if (TREE_CODE (member) == FUNCTION_DECL)
- gen_subprogram_die (member, lookup_type_die (type));
+ gen_subprogram_die (member, type_die);
+ else if (TREE_CODE (member) == FIELD_DECL)
+ {
+ /* Ignore the nameless fields that are used to skip bits but handle
+ C++ anonymous unions and structs. */
+ if (DECL_NAME (member) != NULL_TREE
+ || TREE_CODE (TREE_TYPE (member)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE)
+ {
+ gen_type_die (member_declared_type (member), type_die);
+ gen_field_die (member, type_die);
+ }
+ }
else
- gen_variable_die (member, lookup_type_die (type));
+ gen_variable_die (member, type_die);
pop_decl_scope ();
}
It seems reasonable to use AT_specification in this case. */
&& !get_AT (old_die, DW_AT_inline))
{
- /* ??? This can happen if there is a bug in the program, for
- instance, if it has duplicate function definitions. Ideally,
- we should detect this case and ignore it. For now, if we have
- already reported an error, any error at all, then assume that
- we got here because of an input error, not a dwarf2 bug. */
- gcc_assert (errorcount);
+ /* Detect and ignore this case, where we are trying to output
+ something we have already output. */
return;
}
if (!old_die || !get_AT (old_die, DW_AT_inline))
equate_decl_number_to_die (decl, subr_die);
- ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
- current_function_funcdef_no);
- add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
- ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
- current_function_funcdef_no);
- add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
-
- add_pubname (decl, subr_die);
- add_arange (decl, subr_die);
+ if (!flag_reorder_blocks_and_partition)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
+ current_function_funcdef_no);
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+ current_function_funcdef_no);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
+
+ add_pubname (decl, subr_die);
+ add_arange (decl, subr_die);
+ }
+ else
+ { /* Do nothing for now; maybe need to duplicate die, one for
+ hot section and ond for cold section, then use the hot/cold
+ section begin/end labels to generate the aranges... */
+ /*
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, hot_section_label);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, hot_section_end_label);
+ add_AT_lbl_id (subr_die, DW_AT_lo_user, unlikely_section_label);
+ add_AT_lbl_id (subr_die, DW_AT_hi_user, cold_section_end_label);
+
+ add_pubname (decl, subr_die);
+ add_arange (decl, subr_die);
+ add_arange (decl, subr_die);
+ */
+ }
#ifdef MIPS_DEBUGGING_INFO
/* Add a reference to the FDE for this routine. */
copy decls and set the DECL_ABSTRACT flag on them instead of
sharing them.
- ??? Duplicated blocks have been rewritten to use .debug_ranges. */
- else if (old_die && TREE_STATIC (decl)
+ ??? Duplicated blocks have been rewritten to use .debug_ranges.
+
+ ??? The declare_in_namespace support causes us to get two DIEs for one
+ variable, both of which are declarations. We want to avoid considering
+ one to be a specification, so we must test that this DIE is not a
+ declaration. */
+ else if (old_die && TREE_STATIC (decl) && ! declaration
&& get_AT_flag (old_die, DW_AT_declaration) == 1)
{
/* This is a definition of a C++ class level static. */
}
}
-/* Generate a DIE for a lexical block. */
+/* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
+ Add low_pc and high_pc attributes to the DIE for a block STMT. */
-static void
-gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
+static inline void
+add_high_low_attributes (tree stmt, dw_die_ref die)
{
- dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- if (! BLOCK_ABSTRACT (stmt))
+ if (BLOCK_FRAGMENT_CHAIN (stmt))
{
- if (BLOCK_FRAGMENT_CHAIN (stmt))
- {
- tree chain;
+ tree chain;
- add_AT_range_list (stmt_die, DW_AT_ranges, add_ranges (stmt));
+ add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
- chain = BLOCK_FRAGMENT_CHAIN (stmt);
- do
- {
- add_ranges (chain);
- chain = BLOCK_FRAGMENT_CHAIN (chain);
- }
- while (chain);
- add_ranges (NULL);
- }
- else
+ chain = BLOCK_FRAGMENT_CHAIN (stmt);
+ do
{
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (stmt_die, DW_AT_low_pc, label);
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
+ add_ranges (chain);
+ chain = BLOCK_FRAGMENT_CHAIN (chain);
}
+ while (chain);
+ add_ranges (NULL);
+ }
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+ BLOCK_NUMBER (stmt));
+ add_AT_lbl_id (die, DW_AT_low_pc, label);
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
+ BLOCK_NUMBER (stmt));
+ add_AT_lbl_id (die, DW_AT_high_pc, label);
}
+}
+
+/* Generate a DIE for a lexical block. */
+
+static void
+gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
+{
+ dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+
+ if (! BLOCK_ABSTRACT (stmt))
+ add_high_low_attributes (stmt, stmt_die);
decls_for_scope (stmt, stmt_die, depth);
}
{
dw_die_ref subr_die
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
add_abstract_origin_attribute (subr_die, decl);
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (subr_die, DW_AT_low_pc, label);
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (subr_die, DW_AT_high_pc, label);
+ add_high_low_attributes (stmt, subr_die);
+
decls_for_scope (stmt, subr_die, depth);
current_function_has_inlines = 1;
}
gen_ptr_to_mbr_type_die (type, context_die);
break;
- case FILE_TYPE:
- gen_type_die (TREE_TYPE (type), context_die);
- /* No way to represent these in Dwarf yet! */
- gcc_unreachable ();
- break;
-
case FUNCTION_TYPE:
/* Force out return type (in case it wasn't forced out already). */
gen_type_die (TREE_TYPE (type), context_die);
tree decl;
enum tree_code origin_code;
- /* Ignore blocks never really used to make RTL. */
- if (stmt == NULL_TREE || !TREE_USED (stmt)
- || (!TREE_ASM_WRITTEN (stmt) && !BLOCK_ABSTRACT (stmt)))
+ /* Ignore blocks that are NULL. */
+ if (stmt == NULL_TREE)
return;
/* If the block is one fragment of a non-contiguous block, do not
if (debug_info_level > DINFO_LEVEL_TERSE)
/* We are not in terse mode so *any* local declaration counts
as being a "significant" one. */
- must_output_die = (BLOCK_VARS (stmt) != NULL);
+ must_output_die = (BLOCK_VARS (stmt) != NULL
+ && (TREE_USED (stmt)
+ || TREE_ASM_WRITTEN (stmt)
+ || BLOCK_ABSTRACT (stmt)));
else
/* We are in terse mode, so only local (nested) function
definitions count as "significant" local declarations. */
tree decl;
tree subblocks;
- /* Ignore blocks never really used to make RTL. */
- if (stmt == NULL_TREE || ! TREE_USED (stmt))
+ /* Ignore NULL blocks. */
+ if (stmt == NULL_TREE)
return;
- /* Output the DIEs to represent all of the data objects and typedefs
- declared directly within this block but not within any nested
- sub-blocks. Also, nested function and tag DIEs have been
- generated with a parent of NULL; fix that up now. */
- for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
+ if (TREE_USED (stmt))
{
- dw_die_ref die;
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- die = lookup_decl_die (decl);
- else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
- die = lookup_type_die (TREE_TYPE (decl));
- else
- die = NULL;
-
- if (die != NULL && die->die_parent == NULL)
- add_child_die (context_die, die);
- else
- gen_decl_die (decl, context_die);
+ /* Output the DIEs to represent all of the data objects and typedefs
+ declared directly within this block but not within any nested
+ sub-blocks. Also, nested function and tag DIEs have been
+ generated with a parent of NULL; fix that up now. */
+ for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
+ {
+ dw_die_ref die;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ die = lookup_decl_die (decl);
+ else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
+ die = lookup_type_die (TREE_TYPE (decl));
+ else
+ die = NULL;
+
+ if (die != NULL && die->die_parent == NULL)
+ add_child_die (context_die, die);
+ else
+ gen_decl_die (decl, context_die);
+ }
}
/* If we're at -g1, we're not interested in subblocks. */
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
+ /* If this decl is from an inlined function, then don't try to emit it in its
+ namespace, as we will get confused. It would have already been emitted
+ when the abstract instance of the inline function was emitted anyways. */
+ if (DECL_P (thing) && DECL_ABSTRACT_ORIGIN (thing))
+ return;
+
ns_context = setup_namespace_context (thing, context_die);
if (ns_context != context_die)
if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
at_import_die = force_type_die (TREE_TYPE (decl));
else
- at_import_die = force_decl_die (decl);
+ {
+ at_import_die = lookup_decl_die (decl);
+ if (!at_import_die)
+ {
+ /* If we're trying to avoid duplicate debug info, we may not have
+ emitted the member decl for this field. Emit it now. */
+ if (TREE_CODE (decl) == FIELD_DECL)
+ {
+ tree type = DECL_CONTEXT (decl);
+ dw_die_ref type_context_die;
+
+ if (TYPE_CONTEXT (type))
+ if (TYPE_P (TYPE_CONTEXT (type)))
+ type_context_die = force_type_die (TYPE_CONTEXT (type));
+ else
+ type_context_die = force_decl_die (TYPE_CONTEXT (type));
+ else
+ type_context_die = comp_unit_die;
+ gen_type_die_for_member (type, decl, type_context_die);
+ }
+ at_import_die = force_decl_die (decl);
+ }
+ }
/* OK, now we have DIEs for decl as well as scope. Emit imported die. */
if (TREE_CODE (decl) == NAMESPACE_DECL)
dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
unsigned int blocknum)
{
- function_section (current_function_decl);
+ current_function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
}
static void
dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
{
- function_section (current_function_decl);
+ current_function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
}
newloc->var_loc_note = loc_note;
newloc->next = NULL;
+ if (last_text_section == in_unlikely_executed_text
+ || (last_text_section == in_named
+ && last_text_section_name == unlikely_text_section_name))
+ newloc->section_label = unlikely_section_label;
+ else
+ newloc->section_label = text_section_label;
+
last_insn = loc_note;
last_label = newloc->label;
decl = NOTE_VAR_LOCATION_DECL (loc_note);
- if (DECL_DEBUG_ALIAS_OF (decl))
- decl = DECL_DEBUG_ALIAS_OF (decl);
+ if (DECL_DEBUG_EXPR (decl) && DECL_DEBUG_EXPR_IS_FROM (decl)
+ && DECL_P (DECL_DEBUG_EXPR (decl)))
+ decl = DECL_DEBUG_EXPR (decl);
add_var_loc_to_decl (decl, newloc);
}
if (debug_info_level >= DINFO_LEVEL_NORMAL
&& line != 0)
{
- function_section (current_function_decl);
+ current_function_section (current_function_decl);
/* If requested, emit something human-readable. */
if (flag_debug_asm)
output_ranges ();
}
- /* Have to end the primary source file. */
+ /* Have to end the macro section. */
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
- dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
dw2_asm_output_data (1, 0, "End compilation unit");
}