@@ -2886,6 +2886,10 @@ gtoggle
Common Driver Report Var(flag_gtoggle)
Toggle debug information generation.
+gvariable-location-views
+Common Driver Var(debug_variable_location_views) Init(2)
+Augment variable location lists with progressive views.
+
gvms
Common Driver JoinedOrMissing Negative(gxcoff)
Generate debug information in VMS format.
@@ -358,6 +358,12 @@
#endif
+/* Define if your assembler supports views in dwarf2 .loc directives. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_DWARF2_DEBUG_VIEW
+#endif
+
+
/* Define if your assembler supports the R_PPC64_ENTRY relocation. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_ENTRY_MARKERS
@@ -27756,6 +27756,52 @@ $as_echo "$gcc_cv_as_dwarf2_file_buggy" >&6; }
$as_echo "#define HAVE_AS_DWARF2_DEBUG_LINE 1" >>confdefs.h
+
+ if test $gcc_cv_as_leb128 = yes; then
+ conftest_s="\
+ .file 1 \"conftest.s\"
+ .loc 1 3 0 view .LVU1
+ $insn
+ .data
+ .uleb128 .LVU1
+ .uleb128 .LVU1
+"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for dwarf2 debug_view support" >&5
+$as_echo_n "checking assembler for dwarf2 debug_view support... " >&6; }
+if test "${gcc_cv_as_dwarf2_debug_view+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ gcc_cv_as_dwarf2_debug_view=no
+ if test $in_tree_gas = yes; then
+ if test $in_tree_gas_is_elf = yes \
+ && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 27 \) \* 1000 + 0`
+ then gcc_cv_as_dwarf2_debug_view=yes
+fi
+ elif test x$gcc_cv_as != x; then
+ $as_echo "$conftest_s" > conftest.s
+ if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+ then
+ gcc_cv_as_dwarf2_debug_view=yes
+ else
+ echo "configure: failed program was" >&5
+ cat conftest.s >&5
+ fi
+ rm -f conftest.o conftest.s
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_dwarf2_debug_view" >&5
+$as_echo "$gcc_cv_as_dwarf2_debug_view" >&6; }
+if test $gcc_cv_as_dwarf2_debug_view = yes; then
+
+$as_echo "#define HAVE_AS_DWARF2_DEBUG_VIEW 1" >>confdefs.h
+
+fi
+ fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for --gdwarf2 option" >&5
@@ -4847,9 +4847,25 @@ if test x"$insn" != x; then
if test $gcc_cv_as_dwarf2_debug_line = yes \
&& test $gcc_cv_as_dwarf2_file_buggy = no; then
- AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1,
+ AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1,
[Define if your assembler supports dwarf2 .file/.loc directives,
and preserves file table indices exactly as given.])
+
+ if test $gcc_cv_as_leb128 = yes; then
+ conftest_s="\
+ .file 1 \"conftest.s\"
+ .loc 1 3 0 view .LVU1
+ $insn
+ .data
+ .uleb128 .LVU1
+ .uleb128 .LVU1
+"
+ gcc_GAS_CHECK_FEATURE([dwarf2 debug_view support],
+ gcc_cv_as_dwarf2_debug_view,
+ [elf,2,27,0],,[$conftest_s],,
+ [AC_DEFINE(HAVE_AS_DWARF2_DEBUG_VIEW, 1,
+ [Define if your assembler supports views in dwarf2 .loc directives.])])
+ fi
fi
gcc_GAS_CHECK_FEATURE([--gdwarf2 option],
@@ -345,6 +345,7 @@ Objective-C and Objective-C++ Dialects}.
-gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol
-gcolumn-info -gno-column-info @gol
-gstatement-frontiers -gno-statement-frontiers @gol
+-gvariable-location-views -gno-variable-location-views @gol
-gvms -gxcoff -gxcoff+ -gz@r{[}=@var{type}@r{]} @gol
-fdebug-prefix-map=@var{old}=@var{new} -fdebug-types-section @gol
-feliminate-dwarf2-dups -fno-eliminate-unused-debug-types @gol
@@ -7000,6 +7001,24 @@ markers in the line number table. This is enabled by default when
compiling with optimization (@option{-Os}, @option{-O}, @option{-O2},
@dots{}), and outputting DWARF 2 debug information at the normal level.
+@item -gvariable-location-views
+@item -gno-variable-location-views
+@opindex gvariable-location-views
+@opindex gno-variable-location-views
+Augment variable location lists with progressive view numbers implied
+from the line number table. This enables debug information consumers to
+inspect state at certain points of the program, even if no instructions
+associated with the corresponding source locations are present at that
+point. If the assembler lacks support for view numbers in line number
+tables, this will cause the compiler to emit the line number table,
+which generally makes them somewhat less compact. The augmented line
+number tables and location lists are fully backward-compatible, so they
+can be consumed by debug information consumers that are not aware of
+these augmentations, but they won't derive any benefit from them either.
+This is enabled by default when outputting DWARF 2 debug information at
+the normal level, as long as @code{-fvar-tracking-assignments} is
+enabled and @code{-gstrict-dwarf} is not.
+
@item -gz@r{[}=@var{type}@r{]}
@opindex gz
Produce compressed debug sections in DWARF format, if that is supported.
@@ -768,6 +768,31 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
}
void
+dw2_asm_output_symname_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
+ const char *comment, ...)
+{
+ va_list ap;
+
+ va_start (ap, comment);
+
+#ifdef HAVE_AS_LEB128
+ fputs ("\t.uleb128 ", asm_out_file);
+ assemble_name (asm_out_file, lab1);
+#else
+ gcc_unreachable ();
+#endif
+
+ if (flag_debug_asm && comment)
+ {
+ fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+ vfprintf (asm_out_file, comment, ap);
+ }
+ fputc ('\n', asm_out_file);
+
+ va_end (ap);
+}
+
+void
dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
const char *lab2 ATTRIBUTE_UNUSED,
const char *comment, ...)
@@ -70,6 +70,10 @@ extern void dw2_asm_output_data_sleb128 (HOST_WIDE_INT,
const char *, ...)
ATTRIBUTE_NULL_PRINTF_2;
+extern void dw2_asm_output_symname_uleb128 (const char *,
+ const char *, ...)
+ ATTRIBUTE_NULL_PRINTF_2;
+
extern void dw2_asm_output_delta_uleb128 (const char *, const char *,
const char *, ...)
ATTRIBUTE_NULL_PRINTF_3;
@@ -1275,6 +1275,8 @@ struct GTY((for_user)) addr_table_entry {
GTY ((desc ("%1.kind"))) addr;
};
+typedef unsigned int var_loc_view;
+
/* Location lists are ranges + location descriptions for that range,
so you can track variables that are in different places over
their entire life. */
@@ -1284,9 +1286,11 @@ typedef struct GTY(()) dw_loc_list_struct {
addr_table_entry *begin_entry;
const char *end; /* Label for end of range */
char *ll_symbol; /* Label for beginning of location list.
- Only on head of list */
+ Only on head of list. */
+ char *vl_symbol; /* Label for beginning of view list. Ditto. */
const char *section; /* Section this loclist is relative to */
dw_loc_descr_ref expr;
+ var_loc_view vbegin, vend;
hashval_t hash;
/* True if all addresses in this and subsequent lists are known to be
resolved. */
@@ -1323,6 +1327,31 @@ dwarf_stack_op_name (unsigned int op)
return "OP_<unknown>";
}
+/* Return TRUE iff we're to output location view lists as a separate
+ attribute next to the location lists, as an extension compatible
+ with DWARF 2 and above. */
+
+static inline bool
+dwarf2out_locviews_in_attribute ()
+{
+ return debug_variable_location_views
+ && dwarf_version <= 5;
+}
+
+/* Return TRUE iff we're to output location view lists as part of the
+ location lists, as proposed for standardization after DWARF 5. */
+
+static inline bool
+dwarf2out_locviews_in_loclist ()
+{
+#ifndef DW_LLE_view_pair
+ return false;
+#else
+ return debug_variable_location_views
+ && dwarf_version >= 6;
+#endif
+}
+
/* Return a pointer to a newly allocated location description. Location
descriptions are simple expression terms that can be strung
together to form more complicated location (address) descriptions. */
@@ -1398,6 +1427,8 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b)
return a->v.val_loc == b->v.val_loc;
case dw_val_class_loc_list:
return a->v.val_loc_list == b->v.val_loc_list;
+ case dw_val_class_view_list:
+ return a->v.val_view_list == b->v.val_view_list;
case dw_val_class_die_ref:
return a->v.val_die_ref.die == b->v.val_die_ref.die;
case dw_val_class_fde_ref:
@@ -2835,7 +2866,15 @@ enum dw_line_info_opcode {
LI_set_epilogue_begin,
/* Emit a DW_LNE_set_discriminator. */
- LI_set_discriminator
+ LI_set_discriminator,
+
+ /* Output a Fixed Advance PC; the target PC is the label index; the
+ base PC is the previous LI_adv_address or LI_set_address entry.
+ We only use this when emitting debug views without assembler
+ support, at explicit user request. Ideally, we should only use
+ it when the offset might be zero but we can't tell: it's the only
+ way to maybe change the PC without resetting the view number. */
+ LI_adv_address
};
typedef struct GTY(()) dw_line_info_struct {
@@ -2857,6 +2896,25 @@ struct GTY(()) dw_line_info_table {
bool is_stmt;
bool in_use;
+ /* This denotes the NEXT view number.
+
+ If it is 0, it is known that the NEXT view will be the first view
+ at the given PC.
+
+ If it is -1, we've advanced PC but we haven't emitted a line location yet,
+ so we shouldn't use this view number.
+
+ The meaning of other nonzero values depends on whether we're
+ computing views internally or leaving it for the assembler to do
+ so. If we're emitting them internally, view denotes the view
+ number since the last known advance of PC. If we're leaving it
+ for the assembler, it denotes the LVU label number that we're
+ going to ask the assembler to assign. */
+ var_loc_view view;
+
+#define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0)
+#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0)
+
vec<dw_line_info_entry, va_gc> *entries;
};
@@ -3055,6 +3113,41 @@ skeleton_chain_node;
#endif
#endif
+/* Use assembler views in line directives if available. */
+#ifndef DWARF2_ASM_VIEW_DEBUG_INFO
+#ifdef HAVE_AS_DWARF2_DEBUG_VIEW
+#define DWARF2_ASM_VIEW_DEBUG_INFO 1
+#else
+#define DWARF2_ASM_VIEW_DEBUG_INFO 0
+#endif
+#endif
+
+/* A bit is set in ZERO_VIEW_P if we are using the assembler-supported
+ view computation, and it is refers to a view identifier for which
+ will not emit a label because it is known to map to a view number
+ zero. We won't allocate the bitmap if we're not using assembler
+ support for location views, but we have to make the variable
+ visible for GGC and for code that will be optimized out for lack of
+ support but that's still parsed and compiled. We could abstract it
+ out with macros, but it's not worth it. */
+static GTY(()) bitmap zero_view_p;
+
+/* Evaluate to TRUE iff N is known to identify the first location view
+ at its PC. When not using assembler location view computation,
+ that must be view number zero. Otherwise, ZERO_VIEW_P is allocated
+ and views label numbers recorded in it are the ones known to be
+ zero. */
+#define ZERO_VIEW_P(N) (zero_view_p \
+ ? bitmap_bit_p (zero_view_p, (N)) \
+ : (N) == 0)
+
+static bool
+output_asm_line_debug_info (void)
+{
+ return DWARF2_ASM_VIEW_DEBUG_INFO
+ || (DWARF2_ASM_LINE_DEBUG_INFO && !debug_variable_location_views);
+}
+
/* Minimum line offset in a special line info. opcode.
This value was chosen to give a reasonable range of values. */
#define DWARF_LINE_BASE -10
@@ -3164,6 +3257,7 @@ struct GTY ((chain_next ("%h.next"))) var_loc_node {
rtx GTY (()) loc;
const char * GTY (()) label;
struct var_loc_node * GTY (()) next;
+ var_loc_view view;
};
/* Variable location list. */
@@ -3372,6 +3466,8 @@ static inline dw_loc_descr_ref AT_loc (dw_attr_node *);
static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
dw_loc_list_ref);
static inline dw_loc_list_ref AT_loc_list (dw_attr_node *);
+static void add_AT_view_list (dw_die_ref, enum dwarf_attribute);
+static inline dw_loc_list_ref AT_loc_list (dw_attr_node *);
static addr_table_entry *add_addr_table_entry (void *, enum ate_kind);
static void remove_addr_table_entry (addr_table_entry *);
static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
@@ -3408,7 +3504,7 @@ static void equate_type_number_to_die (tree, dw_die_ref);
static dw_die_ref lookup_decl_die (tree);
static var_loc_list *lookup_decl_loc (const_tree);
static void equate_decl_number_to_die (tree, dw_die_ref);
-static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
+static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *, var_loc_view);
static void print_spaces (FILE *);
static void print_die (dw_die_ref, FILE *);
static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
@@ -3616,8 +3712,8 @@ static void gen_tagged_type_die (tree, dw_die_ref, enum debug_info_usage);
static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage);
static void splice_child_die (dw_die_ref, dw_die_ref);
static int file_info_cmp (const void *, const void *);
-static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
- const char *, const char *);
+static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, var_loc_view,
+ const char *, var_loc_view, const char *);
static void output_loc_list (dw_loc_list_ref);
static char *gen_internal_sym (const char *);
static bool want_pubnames (void);
@@ -4539,11 +4635,55 @@ AT_loc_list (dw_attr_node *a)
return a->dw_attr_val.v.val_loc_list;
}
+static inline void
+add_AT_view_list (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_node attr;
+
+ if (XCOFF_DEBUGGING_INFO && !HAVE_XCOFF_DWARF_EXTRAS)
+ return;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_view_list;
+ attr.dw_attr_val.val_entry = NULL;
+ attr.dw_attr_val.v.val_view_list = die;
+ add_dwarf_attr (die, &attr);
+ gcc_checking_assert (get_AT (die, DW_AT_location));
+ gcc_assert (have_location_lists);
+}
+
static inline dw_loc_list_ref *
AT_loc_list_ptr (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
- return &a->dw_attr_val.v.val_loc_list;
+ gcc_assert (a);
+ switch (AT_class (a))
+ {
+ case dw_val_class_loc_list:
+ return &a->dw_attr_val.v.val_loc_list;
+ case dw_val_class_view_list:
+ {
+ dw_attr_node *l;
+ l = get_AT (a->dw_attr_val.v.val_view_list, DW_AT_location);
+ if (!l)
+ return NULL;
+ gcc_checking_assert (l + 1 == a);
+ return AT_loc_list_ptr (l);
+ }
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static inline dw_val_node *
+view_list_to_loc_list_val_node (dw_val_node *val)
+{
+ gcc_assert (val->val_class == dw_val_class_view_list);
+ dw_attr_node *loc = get_AT (val->v.val_view_list, DW_AT_location);
+ if (!loc)
+ return NULL;
+ gcc_checking_assert (&(loc + 1)->dw_attr_val == val);
+ gcc_assert (AT_class (loc) == dw_val_class_loc_list);
+ return &loc->dw_attr_val;
}
struct addr_hasher : ggc_ptr_hash<addr_table_entry>
@@ -5605,7 +5745,7 @@ adjust_piece_list (rtx *dest, rtx *src, rtx *inner,
/* Add a variable location node to the linked list for DECL. */
static struct var_loc_node *
-add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
+add_var_loc_to_decl (tree decl, rtx loc_note, const char *label, var_loc_view view)
{
unsigned int decl_id;
var_loc_list *temp;
@@ -5696,7 +5836,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
/* TEMP->LAST here is either pointer to the last but one or
last element in the chained list, LAST is pointer to the
last element. */
- if (label && strcmp (last->label, label) == 0)
+ if (label && strcmp (last->label, label) == 0 && last->view == view)
{
/* For SRA optimized variables if there weren't any real
insns since last note, just modify the last node. */
@@ -5712,7 +5852,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
temp->last->next = NULL;
unused = last;
last = temp->last;
- gcc_assert (strcmp (last->label, label) != 0);
+ gcc_assert (strcmp (last->label, label) != 0 || last->view != view);
}
else
{
@@ -5847,6 +5987,12 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
fprintf (outfile, "location list -> label:%s",
val->v.val_loc_list->ll_symbol);
break;
+ case dw_val_class_view_list:
+ val = view_list_to_loc_list_val_node (val);
+ fprintf (outfile, "location list with views -> labels:%s and %s",
+ val->v.val_loc_list->ll_symbol,
+ val->v.val_loc_list->vl_symbol);
+ break;
case dw_val_class_range_list:
fprintf (outfile, "range list");
break;
@@ -8946,6 +9092,7 @@ size_of_die (dw_die_ref die)
}
break;
case dw_val_class_loc_list:
+ case dw_val_class_view_list:
if (dwarf_split_debug_info && dwarf_version >= 5)
{
gcc_assert (AT_loc_list (a)->num_assigned);
@@ -9317,6 +9464,7 @@ value_format (dw_attr_node *a)
gcc_unreachable ();
}
case dw_val_class_loc_list:
+ case dw_val_class_view_list:
if (dwarf_split_debug_info
&& dwarf_version >= 5
&& AT_loc_list (a)->num_assigned)
@@ -9612,7 +9760,8 @@ output_die_symbol (dw_die_ref die)
expression. */
static inline dw_loc_list_ref
-new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
+new_loc_list (dw_loc_descr_ref expr, const char *begin, var_loc_view vbegin,
+ const char *end, var_loc_view vend,
const char *section)
{
dw_loc_list_ref retlist = ggc_cleared_alloc<dw_loc_list_node> ();
@@ -9622,10 +9771,28 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
retlist->end = end;
retlist->expr = expr;
retlist->section = section;
+ retlist->vbegin = vbegin;
+ retlist->vend = vend;
return retlist;
}
+/* Return true iff there's any nonzero view number in the loc list. */
+
+static bool
+loc_list_has_views (dw_loc_list_ref list)
+{
+ if (!debug_variable_location_views)
+ return false;
+
+ for (dw_loc_list_ref loc = list;
+ loc != NULL; loc = loc->dw_loc_next)
+ if (!ZERO_VIEW_P (loc->vbegin) || !ZERO_VIEW_P (loc->vend))
+ return true;
+
+ return false;
+}
+
/* Generate a new internal symbol for this location list node, if it
hasn't got one yet. */
@@ -9634,6 +9801,99 @@ gen_llsym (dw_loc_list_ref list)
{
gcc_assert (!list->ll_symbol);
list->ll_symbol = gen_internal_sym ("LLST");
+
+ if (!loc_list_has_views (list))
+ return;
+
+ if (dwarf2out_locviews_in_attribute ())
+ {
+ /* Use the same label_num for the view list. */
+ label_num--;
+ list->vl_symbol = gen_internal_sym ("LVUS");
+ }
+ else
+ list->vl_symbol = list->ll_symbol;
+}
+
+/* Generate a symbol for the list, but only if we really want to emit
+ it as a list. */
+
+static inline void
+maybe_gen_llsym (dw_loc_list_ref list)
+{
+ if (!list || (!list->dw_loc_next && !loc_list_has_views (list)))
+ return;
+
+ gen_llsym (list);
+}
+
+/* Determine whether or not to skip loc_list entry CURR. If we're not
+ to skip it, and SIZEP is non-null, store the size of CURR->expr's
+ representation in *SIZEP. */
+
+static bool
+skip_loc_list_entry (dw_loc_list_ref curr, unsigned long *sizep = 0)
+{
+ /* Don't output an entry that starts and ends at the same address. */
+ if (strcmp (curr->begin, curr->end) == 0
+ && curr->vbegin == curr->vend && !curr->force)
+ return true;
+
+ unsigned long size = size_of_locs (curr->expr);
+
+ /* If the expression is too large, drop it on the floor. We could
+ perhaps put it into DW_TAG_dwarf_procedure and refer to that
+ in the expression, but >= 64KB expressions for a single value
+ in a single range are unlikely very useful. */
+ if (dwarf_version < 5 && size > 0xffff)
+ return true;
+
+ if (sizep)
+ *sizep = size;
+
+ return false;
+}
+
+/* Output a view pair loclist entry for CURR, if it requires one. */
+
+static void
+dwarf2out_maybe_output_loclist_view_pair (dw_loc_list_ref curr)
+{
+ if (!dwarf2out_locviews_in_loclist ())
+ return;
+
+ if (ZERO_VIEW_P (curr->vbegin) && ZERO_VIEW_P (curr->vend))
+ return;
+
+#ifdef DW_LLE_view_pair
+ dw2_asm_output_data (1, DW_LLE_view_pair,
+ "DW_LLE_view_pair");
+
+# if DWARF2_ASM_VIEW_DEBUG_INFO
+ if (ZERO_VIEW_P (curr->vbegin))
+ dw2_asm_output_data_uleb128 (0, "Location view begin");
+ else
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
+ dw2_asm_output_symname_uleb128 (label, "Location view begin");
+ }
+
+ if (ZERO_VIEW_P (curr->vend))
+ dw2_asm_output_data_uleb128 (0, "Location view end");
+ else
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
+ dw2_asm_output_symname_uleb128 (label, "Location view end");
+ }
+# else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
+ dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin");
+ dw2_asm_output_data_uleb128 (curr->vend, "Location view end");
+# endif /* DWARF2_ASM_VIEW_DEBUG_INFO */
+#endif /* DW_LLE_view_pair */
+
+ return;
}
/* Output the location list given to us. */
@@ -9641,34 +9901,85 @@ gen_llsym (dw_loc_list_ref list)
static void
output_loc_list (dw_loc_list_ref list_head)
{
+ int vcount = 0, lcount = 0;
+
if (list_head->emitted)
return;
list_head->emitted = true;
+ if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ())
+ {
+ ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol);
+
+ for (dw_loc_list_ref curr = list_head; curr != NULL;
+ curr = curr->dw_loc_next)
+ {
+ if (skip_loc_list_entry (curr))
+ continue;
+
+ vcount++;
+
+ /* ?? dwarf_split_debug_info? */
+#if DWARF2_ASM_VIEW_DEBUG_INFO
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (!ZERO_VIEW_P (curr->vbegin))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
+ dw2_asm_output_symname_uleb128 (label,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+ }
+ else
+ dw2_asm_output_data_uleb128 (0,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+
+ if (!ZERO_VIEW_P (curr->vend))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
+ dw2_asm_output_symname_uleb128 (label,
+ "View list end (%s)",
+ list_head->vl_symbol);
+ }
+ else
+ dw2_asm_output_data_uleb128 (0,
+ "View list end (%s)",
+ list_head->vl_symbol);
+#else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
+ dw2_asm_output_data_uleb128 (curr->vbegin,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+ dw2_asm_output_data_uleb128 (curr->vend,
+ "View list end (%s)",
+ list_head->vl_symbol);
+#endif
+ }
+ }
+
ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
- dw_loc_list_ref curr = list_head;
const char *last_section = NULL;
const char *base_label = NULL;
/* Walk the location list, and output each range + expression. */
- for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
+ for (dw_loc_list_ref curr = list_head; curr != NULL;
+ curr = curr->dw_loc_next)
{
unsigned long size;
- /* Don't output an entry that starts and ends at the same address. */
- if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
- continue;
- size = size_of_locs (curr->expr);
- /* If the expression is too large, drop it on the floor. We could
- perhaps put it into DW_TAG_dwarf_procedure and refer to that
- in the expression, but >= 64KB expressions for a single value
- in a single range are unlikely very useful. */
- if (dwarf_version < 5 && size > 0xffff)
+
+ /* Skip this entry? If we skip it here, we must skip it in the
+ view list above as well. */
+ if (skip_loc_list_entry (curr, &size))
continue;
+
+ lcount++;
+
if (dwarf_version >= 5)
{
if (dwarf_split_debug_info)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
/* For -gsplit-dwarf, emit DW_LLE_starx_length, which has
uleb128 index into .debug_addr and uleb128 length. */
dw2_asm_output_data (1, DW_LLE_startx_length,
@@ -9686,6 +9997,7 @@ output_loc_list (dw_loc_list_ref list_head)
}
else if (!have_multiple_function_sections && HAVE_AS_LEB128)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
/* If all code is in .text section, the base address is
already provided by the CU attributes. Use
DW_LLE_offset_pair where both addresses are uleb128 encoded
@@ -9736,6 +10048,7 @@ output_loc_list (dw_loc_list_ref list_head)
length. */
if (last_section == NULL)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_start_length,
"DW_LLE_start_length (%s)",
list_head->ll_symbol);
@@ -9750,6 +10063,7 @@ output_loc_list (dw_loc_list_ref list_head)
DW_LLE_base_address. */
else
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_offset_pair,
"DW_LLE_offset_pair (%s)",
list_head->ll_symbol);
@@ -9765,6 +10079,7 @@ output_loc_list (dw_loc_list_ref list_head)
DW_LLE_start_end with a pair of absolute addresses. */
else
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_start_end,
"DW_LLE_start_end (%s)",
list_head->ll_symbol);
@@ -9843,6 +10158,9 @@ output_loc_list (dw_loc_list_ref list_head)
"Location list terminator end (%s)",
list_head->ll_symbol);
}
+
+ gcc_assert (!list_head->vl_symbol
+ || vcount == lcount * (dwarf2out_locviews_in_attribute () ? 1 : 0));
}
/* Output a range_list offset into the .debug_ranges or .debug_rnglists
@@ -9907,6 +10225,22 @@ output_loc_list_offset (dw_attr_node *a)
"%s", dwarf_attr_name (a->dw_attr));
}
+/* Output the offset into the debug_loc section. */
+
+static void
+output_view_list_offset (dw_attr_node *a)
+{
+ char *sym = (*AT_loc_list_ptr (a))->vl_symbol;
+
+ gcc_assert (sym);
+ if (dwarf_split_debug_info)
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
+ "%s", dwarf_attr_name (a->dw_attr));
+ else
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
+ "%s", dwarf_attr_name (a->dw_attr));
+}
+
/* Output an attribute's index or value appropriately. */
static void
@@ -10137,6 +10471,10 @@ output_die (dw_die_ref die)
output_loc_list_offset (a);
break;
+ case dw_val_class_view_list:
+ output_view_list_offset (a);
+ break;
+
case dw_val_class_die_ref:
if (AT_ref_external (a))
{
@@ -10309,6 +10647,28 @@ output_die (dw_die_ref die)
(unsigned long) die->die_offset);
}
+/* Output the dwarf version number. */
+
+static void
+output_dwarf_version ()
+{
+ /* ??? For now, if -gdwarf-6 is specified, we output version 5 with
+ views in loclist. That will change eventually. */
+ if (dwarf_version == 6)
+ {
+ static bool once;
+ if (!once)
+ {
+ warning (0,
+ "-gdwarf-6 is output as version 5 with incompatibilities");
+ once = true;
+ }
+ dw2_asm_output_data (2, 5, "DWARF version number");
+ }
+ else
+ dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+}
+
/* Output the compilation unit that appears at the beginning of the
.debug_info section, and precedes the DIE descriptions. */
@@ -10325,7 +10685,7 @@ output_compilation_unit_header (enum dwarf_unit_type ut)
"Length of Compilation Unit Info");
}
- dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ output_dwarf_version ();
if (dwarf_version >= 5)
{
const char *name;
@@ -10514,7 +10874,7 @@ output_skeleton_debug_sections (dw_die_ref comp_unit,
- DWARF_INITIAL_LENGTH_SIZE
+ size_of_die (comp_unit),
"Length of Compilation Unit Info");
- dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ output_dwarf_version ();
if (dwarf_version >= 5)
{
dw2_asm_output_data (1, DW_UT_skeleton, "DW_UT_skeleton");
@@ -10813,7 +11173,7 @@ output_pubnames (vec<pubname_entry, va_gc> *names)
}
/* Version number for pubnames/pubtypes is independent of dwarf version. */
- dw2_asm_output_data (2, 2, "DWARF Version");
+ dw2_asm_output_data (2, 2, "DWARF pubnames/pubtypes version");
if (dwarf_split_debug_info)
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
@@ -10895,7 +11255,7 @@ output_aranges (void)
}
/* Version number for aranges is still 2, even up to DWARF5. */
- dw2_asm_output_data (2, 2, "DWARF Version");
+ dw2_asm_output_data (2, 2, "DWARF aranges version");
if (dwarf_split_debug_info)
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
debug_skeleton_info_section,
@@ -11156,7 +11516,7 @@ output_rnglists (void)
dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
"Length of Range Lists");
ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ output_dwarf_version ();
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
dw2_asm_output_data (1, 0, "Segment Size");
/* Emit the offset table only for -gsplit-dwarf. If we don't care
@@ -11790,8 +12150,11 @@ output_one_line_info_table (dw_line_info_table *table)
char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
unsigned int current_line = 1;
bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
- dw_line_info_entry *ent;
+ dw_line_info_entry *ent, *prev_addr;
size_t i;
+ unsigned int view;
+
+ view = 0;
FOR_EACH_VEC_SAFE_ELT (table->entries, i, ent)
{
@@ -11806,14 +12169,36 @@ output_one_line_info_table (dw_line_info_table *table)
to determine when it is safe to use DW_LNS_fixed_advance_pc. */
ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
+ view = 0;
+
/* This can handle any delta. This takes
4+DWARF2_ADDR_SIZE bytes. */
- dw2_asm_output_data (1, 0, "set address %s", line_label);
+ dw2_asm_output_data (1, 0, "set address %s%s", line_label,
+ debug_variable_location_views
+ ? ", reset view to 0" : "");
dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
dw2_asm_output_data (1, DW_LNE_set_address, NULL);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+
+ prev_addr = ent;
break;
+ case LI_adv_address:
+ {
+ ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
+ char prev_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (prev_label, LINE_CODE_LABEL, prev_addr->val);
+
+ view++;
+
+ dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, "fixed advance PC, increment view to %i", view);
+ dw2_asm_output_delta (2, line_label, prev_label,
+ "from %s to %s", prev_label, line_label);
+
+ prev_addr = ent;
+ break;
+ }
+
case LI_set_line:
if (ent->val == current_line)
{
@@ -11921,7 +12306,7 @@ output_line_info (bool prologue_only)
ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ output_dwarf_version ();
if (dwarf_version >= 5)
{
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
@@ -16214,6 +16599,7 @@ static dw_loc_list_ref
dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
{
const char *endname, *secname;
+ var_loc_view endview;
rtx varloc;
enum var_init_status initialized;
struct var_loc_node *node;
@@ -16269,24 +16655,27 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
&& current_function_decl)
{
endname = cfun->fde->dw_fde_end;
+ endview = 0;
range_across_switch = true;
}
/* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */
else if (node->next)
- endname = node->next->label;
+ endname = node->next->label, endview = node->next->view;
/* If the variable has a location at the last label
it keeps its location until the end of function. */
else if (!current_function_decl)
- endname = text_end_label;
+ endname = text_end_label, endview = 0;
else
{
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
endname = ggc_strdup (label_id);
+ endview = 0;
}
- *listp = new_loc_list (descr, node->label, endname, secname);
+ *listp = new_loc_list (descr, node->label, node->view,
+ endname, endview, secname);
if (TREE_CODE (decl) == PARM_DECL
&& node == loc_list->first
&& NOTE_P (node->loc)
@@ -16309,12 +16698,12 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
/* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */
if (node->next)
- endname = node->next->label;
+ endname = node->next->label, endview = node->next->view;
else
- endname = cfun->fde->dw_fde_second_end;
+ endname = cfun->fde->dw_fde_second_end, endview = 0;
*listp = new_loc_list (descr,
- cfun->fde->dw_fde_second_begin,
- endname, secname);
+ cfun->fde->dw_fde_second_begin, 0,
+ endname, endview, secname);
listp = &(*listp)->dw_loc_next;
}
}
@@ -16326,8 +16715,7 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
representable, we don't want to pretend a single entry that was
applies to the entire scope in which the variable is
available. */
- if (list && loc_list->first->next)
- gen_llsym (list);
+ maybe_gen_llsym (list);
return list;
}
@@ -17147,7 +17535,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
{
if (dwarf_version >= 3 || !dwarf_strict)
return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0),
- NULL, NULL, NULL);
+ NULL, 0, NULL, 0, NULL);
else
return NULL;
}
@@ -17960,7 +18348,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
}
if (ret)
- list_ret = new_loc_list (ret, NULL, NULL, NULL);
+ list_ret = new_loc_list (ret, NULL, 0, NULL, 0, NULL);
return list_ret;
}
@@ -18284,12 +18672,25 @@ static inline void
add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
dw_loc_list_ref descr)
{
+ bool check_no_locviews = true;
if (descr == 0)
return;
if (single_element_loc_list_p (descr))
add_AT_loc (die, attr_kind, descr->expr);
else
- add_AT_loc_list (die, attr_kind, descr);
+ {
+ add_AT_loc_list (die, attr_kind, descr);
+ gcc_assert (descr->ll_symbol);
+ if (attr_kind == DW_AT_location && descr->vl_symbol
+ && dwarf2out_locviews_in_attribute ())
+ {
+ add_AT_view_list (die, DW_AT_GNU_locviews);
+ check_no_locviews = false;
+ }
+ }
+
+ if (check_no_locviews)
+ gcc_assert (!get_AT (die, DW_AT_GNU_locviews));
}
/* Add DW_AT_accessibility attribute to DIE if needed. */
@@ -19459,7 +19860,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
/* If the first partition contained no CFI adjustments, the
CIE opcodes apply to the whole first partition. */
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- fde->dw_fde_begin, fde->dw_fde_end, section);
+ fde->dw_fde_begin, 0, fde->dw_fde_end, 0, section);
list_tail =&(*list_tail)->dw_loc_next;
start_label = last_label = fde->dw_fde_second_begin;
}
@@ -19475,7 +19876,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
last_cfa = next_cfa;
@@ -19497,14 +19898,14 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
last_cfa = next_cfa;
start_label = last_label;
}
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, fde->dw_fde_end, section);
+ start_label, 0, fde->dw_fde_end, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
start_label = last_label = fde->dw_fde_second_begin;
}
@@ -19513,19 +19914,18 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
start_label = last_label;
}
*list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
- start_label,
+ start_label, 0,
fde->dw_fde_second_begin
- ? fde->dw_fde_second_end : fde->dw_fde_end,
+ ? fde->dw_fde_second_end : fde->dw_fde_end, 0,
section);
- if (list && list->dw_loc_next)
- gen_llsym (list);
+ maybe_gen_llsym (list);
return list;
}
@@ -25922,7 +26322,7 @@ maybe_emit_file (struct dwarf_file_data * fd)
fd->emitted_number = 1;
last_emitted_file = fd;
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
{
fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
output_quoted_string (asm_out_file,
@@ -26115,11 +26515,13 @@ dwarf2out_var_location (rtx_insn *loc_note)
static rtx_insn *expected_next_loc_note;
tree decl;
bool var_loc_p;
+ var_loc_view view = 0;
if (!NOTE_P (loc_note))
{
if (CALL_P (loc_note))
{
+ RESET_NEXT_VIEW (cur_line_info_table->view);
call_site_count++;
if (SIBLING_CALL_P (loc_note))
tail_call_site_count++;
@@ -26153,6 +26555,18 @@ dwarf2out_var_location (rtx_insn *loc_note)
}
}
}
+ else if (!debug_variable_location_views)
+ gcc_unreachable ();
+ else if (JUMP_TABLE_DATA_P (loc_note))
+ RESET_NEXT_VIEW (cur_line_info_table->view);
+ else if (GET_CODE (loc_note) == USE
+ || GET_CODE (loc_note) == CLOBBER
+ || GET_CODE (loc_note) == ASM_INPUT
+ || asm_noperands (loc_note) >= 0)
+ ;
+ else if (get_attr_min_length (loc_note) > 0)
+ RESET_NEXT_VIEW (cur_line_info_table->view);
+
return;
}
@@ -26216,10 +26630,11 @@ create_label:
if (var_loc_p)
{
+ const char *label = NOTE_DURING_CALL_P (loc_note)
+ ? last_postcall_label : last_label;
+ view = cur_line_info_table->view;
decl = NOTE_VAR_LOCATION_DECL (loc_note);
- newloc = add_var_loc_to_decl (decl, loc_note,
- NOTE_DURING_CALL_P (loc_note)
- ? last_postcall_label : last_label);
+ newloc = add_var_loc_to_decl (decl, loc_note, label, view);
if (newloc == NULL)
return;
}
@@ -26260,8 +26675,8 @@ create_label:
else if (GET_CODE (body) == ASM_INPUT
|| asm_noperands (body) >= 0)
continue;
-#ifdef HAVE_attr_length
- else if (get_attr_min_length (insn) == 0)
+#ifdef HAVE_ATTR_length /* ??? We don't include insn-attr.h. */
+ else if (HAVE_ATTR_length && get_attr_min_length (insn) == 0)
continue;
#endif
else
@@ -26329,7 +26744,10 @@ create_label:
call_arg_loc_last = ca_loc;
}
else if (loc_note != NULL_RTX && !NOTE_DURING_CALL_P (loc_note))
- newloc->label = last_label;
+ {
+ newloc->label = last_label;
+ newloc->view = view;
+ }
else
{
if (!last_postcall_label)
@@ -26338,6 +26756,7 @@ create_label:
last_postcall_label = ggc_strdup (loclabel);
}
newloc->label = last_postcall_label;
+ newloc->view = view;
}
if (var_loc_p && flag_debug_asm)
@@ -26404,6 +26823,7 @@ new_line_info_table (void)
table->file_num = 1;
table->line_num = 1;
table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
+ RESET_NEXT_VIEW (table->view);
return table;
}
@@ -26452,7 +26872,7 @@ set_cur_line_info_table (section *sec)
vec_safe_push (separate_line_info, table);
}
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
table->is_stmt = (cur_line_info_table
? cur_line_info_table->is_stmt
: DWARF_LINE_DEFAULT_IS_STMT_START);
@@ -26633,7 +27053,7 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
filename, line);
}
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
{
/* Emit the .loc directive understood by GNU as. */
/* "\t.loc %u %u 0 is_stmt %u discriminator %u",
@@ -26659,6 +27079,33 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
fputs (" discriminator ", asm_out_file);
fprint_ul (asm_out_file, (unsigned long) discriminator);
}
+ if (debug_variable_location_views)
+ {
+ static var_loc_view lvugid;
+ if (!lvugid)
+ {
+ gcc_assert (!zero_view_p);
+ zero_view_p = BITMAP_GGC_ALLOC ();
+ bitmap_set_bit (zero_view_p, 0);
+ }
+ if (RESETTING_VIEW_P (table->view))
+ {
+ if (!table->in_use)
+ fputs (" view -0", asm_out_file);
+ else
+ fputs (" view 0", asm_out_file);
+ bitmap_set_bit (zero_view_p, lvugid);
+ table->view = ++lvugid;
+ }
+ else
+ {
+ fputs (" view ", asm_out_file);
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view);
+ assemble_name (asm_out_file, label);
+ table->view = ++lvugid;
+ }
+ }
putc ('\n', asm_out_file);
}
else
@@ -26667,7 +27114,19 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
- push_dw_line_info_entry (table, LI_set_address, label_num);
+ if (debug_variable_location_views && table->view)
+ push_dw_line_info_entry (table, LI_adv_address, label_num);
+ else
+ push_dw_line_info_entry (table, LI_set_address, label_num);
+ if (debug_variable_location_views)
+ {
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s view %s%d\n",
+ ASM_COMMENT_START,
+ table->in_use ? "" : "-",
+ table->view);
+ table->view++;
+ }
if (file_num != table->file_num)
push_dw_line_info_entry (table, LI_set_file, file_num);
if (discriminator != table->discrim_num)
@@ -27256,7 +27715,7 @@ init_sections_and_labels (void)
SECTION_DEBUG, NULL);
debug_str_section = get_section (DEBUG_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
- if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+ if (!dwarf_split_debug_info && !output_asm_line_debug_info ())
debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
@@ -27641,6 +28100,11 @@ prune_unused_types_walk_attribs (dw_die_ref die)
prune_unused_types_walk_loc_descr (list->expr);
break;
+ case dw_val_class_view_list:
+ /* This points to a loc_list in another attribute, so it's
+ already covered. */
+ break;
+
case dw_val_class_die_ref:
/* A reference to another DIE.
Make sure that it will get emitted.
@@ -28740,6 +29204,8 @@ optimize_string_length (dw_attr_node *a)
if (d->expr && non_dwarf_expression (d->expr))
non_dwarf_expr = true;
break;
+ case dw_val_class_view_list:
+ gcc_unreachable ();
case dw_val_class_loc:
lv = AT_loc (av);
if (lv == NULL)
@@ -28784,7 +29250,7 @@ optimize_string_length (dw_attr_node *a)
lv = copy_deref_exprloc (d->expr);
if (lv)
{
- *p = new_loc_list (lv, d->begin, d->end, d->section);
+ *p = new_loc_list (lv, d->begin, d->vbegin, d->end, d->vend, d->section);
p = &(*p)->dw_loc_next;
}
else if (!dwarf_strict && d->expr)
@@ -28854,6 +29320,7 @@ resolve_addr (dw_die_ref die)
{
gcc_assert (!next->ll_symbol);
next->ll_symbol = (*curr)->ll_symbol;
+ next->vl_symbol = (*curr)->vl_symbol;
}
if (dwarf_split_debug_info)
remove_loc_list_addr_table_entries (l);
@@ -28879,6 +29346,21 @@ resolve_addr (dw_die_ref die)
ix--;
}
break;
+ case dw_val_class_view_list:
+ {
+ gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews);
+ gcc_checking_assert (dwarf2out_locviews_in_attribute ());
+ dw_val_node *llnode
+ = view_list_to_loc_list_val_node (&a->dw_attr_val);
+ /* If we no longer have a loclist, or it no longer needs
+ views, drop this attribute. */
+ if (!llnode || !llnode->v.val_loc_list->vl_symbol)
+ {
+ remove_AT (die, a->dw_attr);
+ ix--;
+ }
+ break;
+ }
case dw_val_class_loc:
{
dw_loc_descr_ref l = AT_loc (a);
@@ -29275,6 +29757,8 @@ hash_loc_list (dw_loc_list_ref list_head)
{
hstate.add (curr->begin, strlen (curr->begin) + 1);
hstate.add (curr->end, strlen (curr->end) + 1);
+ hstate.add_object (curr->vbegin);
+ hstate.add_object (curr->vend);
if (curr->section)
hstate.add (curr->section, strlen (curr->section) + 1);
hash_locs (curr->expr, hstate);
@@ -29496,6 +29980,7 @@ loc_list_hasher::equal (const dw_loc_list_struct *a,
|| strcmp (a->end, b->end) != 0
|| (a->section == NULL) != (b->section == NULL)
|| (a->section && strcmp (a->section, b->section) != 0)
+ || a->vbegin != b->vbegin || a->vend != b->vend
|| !compare_locs (a->expr, b->expr))
break;
return a == NULL && b == NULL;
@@ -29514,6 +29999,8 @@ optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab)
dw_attr_node *a;
unsigned ix;
dw_loc_list_struct **slot;
+ bool drop_locviews = false;
+ bool has_locviews = false;
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
if (AT_class (a) == dw_val_class_loc_list)
@@ -29524,11 +30011,33 @@ optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab)
hash_loc_list (list);
slot = htab->find_slot_with_hash (list, list->hash, INSERT);
if (*slot == NULL)
- *slot = list;
+ {
+ *slot = list;
+ if (loc_list_has_views (list))
+ gcc_assert (list->vl_symbol);
+ else if (list->vl_symbol)
+ {
+ drop_locviews = true;
+ list->vl_symbol = NULL;
+ }
+ }
else
- a->dw_attr_val.v.val_loc_list = *slot;
+ {
+ if (list->vl_symbol && !(*slot)->vl_symbol)
+ drop_locviews = true;
+ a->dw_attr_val.v.val_loc_list = *slot;
+ }
+ }
+ else if (AT_class (a) == dw_val_class_view_list)
+ {
+ gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews);
+ has_locviews = true;
}
+
+ if (drop_locviews && has_locviews)
+ remove_AT (die, DW_AT_GNU_locviews);
+
FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
}
@@ -29553,7 +30062,7 @@ index_location_lists (dw_die_ref die)
/* Don't index an entry that has already been indexed
or won't be output. */
if (curr->begin_entry != NULL
- || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
+ || skip_loc_list_entry (curr))
continue;
curr->begin_entry
@@ -29930,7 +30439,7 @@ dwarf2out_finish (const char *)
dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
"Length of Location Lists");
ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ output_dwarf_version ();
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
dw2_asm_output_data (1, 0, "Segment Size");
dw2_asm_output_data (4, dwarf_split_debug_info ? loc_list_idx : 0,
@@ -29988,7 +30497,7 @@ dwarf2out_finish (const char *)
used by the debug_info section are marked as 'used'. */
switch_to_section (debug_line_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
- if (! DWARF2_ASM_LINE_DEBUG_INFO)
+ if (! output_asm_line_debug_info ())
output_line_info (false);
if (dwarf_split_debug_info && info_section_emitted)
@@ -157,7 +157,8 @@ enum dw_val_class
dw_val_class_discr_list,
dw_val_class_const_implicit,
dw_val_class_unsigned_const_implicit,
- dw_val_class_file_implicit
+ dw_val_class_file_implicit,
+ dw_val_class_view_list
};
/* Describe a floating point constant value, or a vector constant value. */
@@ -200,6 +201,7 @@ struct GTY(()) dw_val_node {
rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset;
dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
+ dw_die_ref GTY ((tag ("dw_val_class_view_list"))) val_view_list;
dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
HOST_WIDE_INT GTY ((default)) val_int;
unsigned HOST_WIDE_INT
@@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see
#include "asan.h"
#include "rtl-iter.h"
#include "print-rtl.h"
+#include "langhooks.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data declarations. */
@@ -112,6 +113,7 @@ along with GCC; see the file COPYING3. If not see
/* Bitflags used by final_scan_insn. */
#define SEEN_NOTE 1
#define SEEN_EMITTED 2
+#define SEEN_NEXT_VIEW 4
/* Last insn processed by final_scan_insn. */
static rtx_insn *debug_insn;
@@ -1759,6 +1761,44 @@ get_some_local_dynamic_name ()
return 0;
}
+/* Arrange for us to emit a source location note before any further
+ real insns or section changes, by setting the SEEN_NEXT_VIEW bit in
+ *SEEN, as long as we are keeping track of location views. The bit
+ indicates we have referenced the next view at the current PC, so we
+ have to emit it. This should be called next to the var_location
+ debug hook. */
+
+static inline void
+set_next_view_needed (int *seen)
+{
+ if (debug_variable_location_views)
+ *seen |= SEEN_NEXT_VIEW;
+}
+
+/* Clear the flag in *SEEN indicating we need to emit the next view.
+ This should be called next to the source_line debug hook. */
+
+static inline void
+clear_next_view_needed (int *seen)
+{
+ *seen &= ~SEEN_NEXT_VIEW;
+}
+
+/* Test whether we have a pending request to emit the next view in
+ *SEEN, and emit it if needed, clearing the request bit. */
+
+static inline void
+maybe_output_next_view (int *seen)
+{
+ if ((*seen & SEEN_NEXT_VIEW) != 0)
+ {
+ clear_next_view_needed (seen);
+ (*debug_hooks->source_line) (last_linenum, last_columnnum,
+ last_filename, last_discriminator,
+ false);
+ }
+}
+
/* Output assembler code for the start of a function,
and initialize some of the variables in this file
for the new function. The label for the function and associated
@@ -1766,12 +1806,15 @@ get_some_local_dynamic_name ()
FIRST is the first insn of the rtl for the function being compiled.
FILE is the file to write assembler code to.
+ SEEN should be initially set to zero, and it may be updated to
+ indicate we have references to the next location view, that would
+ require us to emit it at the current PC.
OPTIMIZE_P is nonzero if we should eliminate redundant
test and compare insns. */
-void
-final_start_function (rtx_insn **firstp, FILE *file,
- int optimize_p ATTRIBUTE_UNUSED)
+static void
+final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
+ int optimize_p ATTRIBUTE_UNUSED)
{
rtx_insn *first = *firstp;
@@ -1792,7 +1835,28 @@ final_start_function (rtx_insn **firstp, FILE *file,
asan_function_start ();
if (!DECL_IGNORED_P (current_function_decl))
- debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
+ {
+ /* Emit param bindings (before the first begin_stmt) in the
+ initial view. We don't test whether the DECLs are
+ PARM_DECLs: the assumption is that there will be a
+ NOTE_INSN_BEGIN_STMT marker before any non-parameter
+ NOTE_INSN_VAR_LOCATION. It's ok if the marker is not there,
+ we'll just have more variable locations bound in the initial
+ view, which is consistent with their being bound without any
+ code that would give them a value. */
+ if (debug_variable_location_views)
+ {
+ rtx_insn *insn;
+ for (insn = first;
+ insn && GET_CODE (insn) == NOTE
+ && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;
+ insn = NEXT_INSN (insn))
+ final_scan_insn (insn, file, 0, 0, seen);
+ *firstp = insn;
+ }
+ debug_hooks->begin_prologue (last_linenum, last_columnnum,
+ last_filename);
+ }
if (!dwarf2_debug_info_emitted_p (current_function_decl))
dwarf2out_begin_prologue (0, 0, NULL);
@@ -1867,6 +1931,17 @@ final_start_function (rtx_insn **firstp, FILE *file,
profile_after_prologue (file);
}
+/* This is an exported final_start_function_1, callable without SEEN. */
+
+void
+final_start_function (rtx_insn **firstp, FILE *file,
+ int optimize_p ATTRIBUTE_UNUSED)
+{
+ int seen = 0;
+ final_start_function_1 (firstp, file, &seen, optimize_p);
+ gcc_assert (seen == 0);
+}
+
static void
profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
{
@@ -1998,11 +2073,10 @@ dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb,
/* Output assembler code for some insns: all or part of a function.
For description of args, see `final_start_function', above. */
-void
-final (rtx_insn *first, FILE *file, int optimize_p)
+static void
+final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p)
{
rtx_insn *insn, *next;
- int seen = 0;
/* Used for -dA dump. */
basic_block *start_to_bb = NULL;
@@ -2069,6 +2143,8 @@ final (rtx_insn *first, FILE *file, int optimize_p)
insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
}
+ maybe_output_next_view (&seen);
+
if (flag_debug_asm)
{
free (start_to_bb);
@@ -2085,6 +2161,14 @@ final (rtx_insn *first, FILE *file, int optimize_p)
delete_insn (insn);
}
}
+
+/* This is an exported final_1, callable without SEEN. */
+
+void
+final (rtx_insn *first, FILE *file, int optimize_p)
+{
+ final_1 (first, file, 0, optimize_p);
+}
const char *
get_insn_template (int code, rtx insn)
@@ -2224,6 +2308,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
break;
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+ maybe_output_next_view (seen);
+
in_cold_section_p = !in_cold_section_p;
if (dwarf2out_do_frame ())
@@ -2364,6 +2450,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
break;
case NOTE_INSN_BLOCK_END:
+ maybe_output_next_view (seen);
+
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF2_DEBUG
@@ -2421,7 +2509,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
case NOTE_INSN_VAR_LOCATION:
case NOTE_INSN_CALL_ARG_LOCATION:
if (!DECL_IGNORED_P (current_function_decl))
- debug_hooks->var_location (insn);
+ {
+ debug_hooks->var_location (insn);
+ set_next_view_needed (seen);
+ }
break;
case NOTE_INSN_BEGIN_STMT:
@@ -2432,6 +2523,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
(*debug_hooks->source_line) (last_linenum, last_columnnum,
last_filename, last_discriminator,
true);
+ clear_next_view_needed (seen);
}
break;
@@ -2628,6 +2720,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
switch_to_section (current_function_section ());
+ if (debug_variable_location_views
+ && !DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
+
break;
}
/* Output this line note if it is the first or the last line
@@ -2640,7 +2736,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
(*debug_hooks->source_line) (last_linenum, last_columnnum,
last_filename, last_discriminator,
is_stmt);
+ clear_next_view_needed (seen);
}
+ else
+ maybe_output_next_view (seen);
+
+ gcc_checking_assert (!DEBUG_INSN_P (insn));
if (GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
@@ -3107,7 +3208,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
/* Let the debug info back-end know about this call. We do this only
after the instruction has been emitted because labels that may be
created to reference the call instruction must appear after it. */
- if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl))
+ if ((debug_variable_location_views || call_insn != NULL)
+ && !DECL_IGNORED_P (current_function_decl))
debug_hooks->var_location (insn);
current_output_insn = debug_insn = 0;
@@ -4547,8 +4649,9 @@ rest_of_handle_final (void)
assemble_start_function (current_function_decl, fnname);
rtx_insn *first = get_insns ();
- final_start_function (&first, asm_out_file, optimize);
- final (first, asm_out_file, optimize);
+ int seen = 0;
+ final_start_function_1 (&first, asm_out_file, &seen, optimize);
+ final_1 (first, asm_out_file, seen, optimize);
if (flag_ipa_ra
&& !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
collect_fn_hard_reg_usage ();
@@ -2329,7 +2329,7 @@ common_handle_option (struct gcc_options *opts,
/* FALLTHRU */
case OPT_gdwarf_:
- if (value < 2 || value > 5)
+ if (value < 2 || value > 6)
error_at (loc, "dwarf version %d is not supported", value);
else
opts->x_dwarf_version = value;
@@ -1538,6 +1538,14 @@ process_options (void)
debug_nonbind_markers_p = optimize && debug_info_level >= DINFO_LEVEL_NORMAL
&& (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG);
+ if (debug_variable_location_views == AUTODETECT_VALUE)
+ {
+ debug_variable_location_views = flag_var_tracking
+ && debug_info_level >= DINFO_LEVEL_NORMAL
+ && (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+ && !dwarf_strict;
+ }
+
if (flag_tree_cselim == AUTODETECT_VALUE)
{
if (HAVE_conditional_move)
@@ -443,6 +443,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
/* Attribute for discriminator.
See http://gcc.gnu.org/wiki/Discriminator */
DW_AT (DW_AT_GNU_discriminator, 0x2136)
+DW_AT (DW_AT_GNU_locviews, 0x2137)
/* VMS extensions. */
DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
/* GNAT extensions. */
@@ -296,6 +296,14 @@ enum dwarf_location_list_entry_type
DW_LLE_start_end = 0x07,
DW_LLE_start_length = 0x08,
+ /* <http://lists.dwarfstd.org/private.cgi/dwarf-discuss-dwarfstd.org/2017-April/004347.html>
+ has the proposal for now; only available to list members.
+
+ A (possibly updated) copy of the proposal is available at
+ <http://people.redhat.com/aoliva/papers/sfn/dwarf6-sfn-lvu.txt>. */
+ DW_LLE_GNU_view_pair = 0x09,
+#define DW_LLE_view_pair DW_LLE_GNU_view_pair
+
/* Former extension for Fission.
See http://gcc.gnu.org/wiki/DebugFission. */
DW_LLE_GNU_end_of_list_entry = 0x00,