static void dwarf2out_source_line (unsigned int, const char *, int, bool);
static rtx last_var_location_insn;
+static rtx cached_next_real_insn;
#ifdef VMS_DEBUGGING_INFO
int vms_file_stats_name (const char *, long long *, long *, char *, int *);
char *section_start_label, int fde_encoding, char *augmentation,
bool any_lsda_needed, int lsda_encoding)
{
- int ix;
const char *begin, *end;
static unsigned int j;
char l1[20], l2[20];
- dw_cfi_ref cfi;
targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh,
/* empty */ 0);
dw2_asm_output_data_uleb128 (0, "Augmentation size");
}
- /* Loop through the Call Frame Instructions associated with
- this FDE. */
+ /* Loop through the Call Frame Instructions associated with this FDE. */
fde->dw_fde_current_label = begin;
- if (fde->dw_fde_second_begin == NULL)
- FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
- output_cfi (cfi, fde, for_eh);
- else if (!second)
- {
- if (fde->dw_fde_switch_cfi_index > 0)
- FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
- {
- if (ix == fde->dw_fde_switch_cfi_index)
- break;
- output_cfi (cfi, fde, for_eh);
- }
- }
- else
- {
- int i, from = 0;
- int until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+ {
+ size_t from, until, i;
- if (fde->dw_fde_switch_cfi_index > 0)
- {
- from = fde->dw_fde_switch_cfi_index;
- output_cfis (fde->dw_fde_cfi, from, false, fde, for_eh);
- }
- for (i = from; i < until; i++)
- output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i),
- fde, for_eh);
- }
+ from = 0;
+ until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+
+ if (fde->dw_fde_second_begin == NULL)
+ ;
+ else if (!second)
+ until = fde->dw_fde_switch_cfi_index;
+ else
+ from = fde->dw_fde_switch_cfi_index;
+
+ for (i = from; i < until; i++)
+ output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i), fde, for_eh);
+ }
/* If we are to emit a ref/link from function bodies to their frame tables,
do it now. This is typically performed to make sure that tables
char label[MAX_ARTIFICIAL_LABEL_BYTES];
last_var_location_insn = NULL_RTX;
+ cached_next_real_insn = NULL_RTX;
if (dwarf2out_do_cfi_asm ())
fprintf (asm_out_file, "\t.cfi_endproc\n");
= (sect == text_section
|| (cold_text_section && sect == cold_text_section));
- fde->dw_fde_switch_cfi_index = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
-
if (dwarf2out_do_cfi_asm ())
- {
- dwarf2out_do_cfi_startproc (true);
- /* As this is a different FDE, insert all current CFI instructions
- again. */
- output_cfis (fde->dw_fde_cfi, fde->dw_fde_switch_cfi_index,
- true, fde, true);
- }
+ dwarf2out_do_cfi_startproc (true);
var_location_switch_text_section ();
*d = descr;
}
+/* Compare two location operands for exact equality. */
+
+static bool
+dw_val_equal_p (dw_val_node *a, dw_val_node *b)
+{
+ if (a->val_class != b->val_class)
+ return false;
+ switch (a->val_class)
+ {
+ case dw_val_class_none:
+ return true;
+ case dw_val_class_addr:
+ return rtx_equal_p (a->v.val_addr, b->v.val_addr);
+
+ case dw_val_class_offset:
+ case dw_val_class_unsigned_const:
+ case dw_val_class_const:
+ case dw_val_class_range_list:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ /* These are all HOST_WIDE_INT, signed or unsigned. */
+ return a->v.val_unsigned == b->v.val_unsigned;
+
+ case dw_val_class_loc:
+ 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_die_ref:
+ return a->v.val_die_ref.die == b->v.val_die_ref.die;
+ case dw_val_class_fde_ref:
+ return a->v.val_fde_index == b->v.val_fde_index;
+ case dw_val_class_lbl_id:
+ return strcmp (a->v.val_lbl_id, b->v.val_lbl_id) == 0;
+ case dw_val_class_str:
+ return a->v.val_str == b->v.val_str;
+ case dw_val_class_flag:
+ return a->v.val_flag == b->v.val_flag;
+ case dw_val_class_file:
+ return a->v.val_file == b->v.val_file;
+ case dw_val_class_decl_ref:
+ return a->v.val_decl_ref == b->v.val_decl_ref;
+
+ case dw_val_class_const_double:
+ return (a->v.val_double.high == b->v.val_double.high
+ && a->v.val_double.low == b->v.val_double.low);
+
+ case dw_val_class_vec:
+ {
+ size_t a_len = a->v.val_vec.elt_size * a->v.val_vec.length;
+ size_t b_len = b->v.val_vec.elt_size * b->v.val_vec.length;
+
+ return (a_len == b_len
+ && !memcmp (a->v.val_vec.array, b->v.val_vec.array, a_len));
+ }
+
+ case dw_val_class_data8:
+ return memcmp (a->v.val_data8, b->v.val_data8, 8) == 0;
+
+ case dw_val_class_vms_delta:
+ return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)
+ && !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1));
+ }
+ gcc_unreachable ();
+}
+
+/* Compare two location atoms for exact equality. */
+
+static bool
+loc_descr_equal_p_1 (dw_loc_descr_ref a, dw_loc_descr_ref b)
+{
+ if (a->dw_loc_opc != b->dw_loc_opc)
+ return false;
+
+ /* ??? This is only ever set for DW_OP_constNu, for N equal to the
+ address size, but since we always allocate cleared storage it
+ should be zero for other types of locations. */
+ if (a->dtprel != b->dtprel)
+ return false;
+
+ return (dw_val_equal_p (&a->dw_loc_oprnd1, &b->dw_loc_oprnd1)
+ && dw_val_equal_p (&a->dw_loc_oprnd2, &b->dw_loc_oprnd2));
+}
+
+/* Compare two complete location expressions for exact equality. */
+
+bool
+loc_descr_equal_p (dw_loc_descr_ref a, dw_loc_descr_ref b)
+{
+ while (1)
+ {
+ if (a == b)
+ return true;
+ if (a == NULL || b == NULL)
+ return false;
+ if (!loc_descr_equal_p_1 (a, b))
+ return false;
+
+ a = a->dw_loc_next;
+ b = b->dw_loc_next;
+ }
+}
+
+
/* Add a constant OFFSET to a location expression. */
static void
/* A structure to hold a macinfo entry. */
typedef struct GTY(()) macinfo_struct {
- unsigned HOST_WIDE_INT code;
+ unsigned char code;
unsigned HOST_WIDE_INT lineno;
const char *info;
}
#ifndef DEBUG_MACINFO_SECTION
#define DEBUG_MACINFO_SECTION ".debug_macinfo"
#endif
+#ifndef DEBUG_MACRO_SECTION
+#define DEBUG_MACRO_SECTION ".debug_macro"
+#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
#ifndef DEBUG_MACINFO_SECTION_LABEL
#define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo"
#endif
+#ifndef DEBUG_MACRO_SECTION_LABEL
+#define DEBUG_MACRO_SECTION_LABEL "Ldebug_macro"
+#endif
/* Definitions of defaults for formats and names of various special
return "DW_AT_GNU_all_call_sites";
case DW_AT_GNU_all_source_call_sites:
return "DW_AT_GNU_all_source_call_sites";
+ case DW_AT_GNU_macros:
+ return "DW_AT_GNU_macros";
case DW_AT_GNAT_descriptive_type:
return "DW_AT_GNAT_descriptive_type";
size += size_of_sleb128 (AT_int (a));
break;
case dw_val_class_unsigned_const:
- size += constant_size (AT_unsigned (a));
+ {
+ int csize = constant_size (AT_unsigned (a));
+ if (dwarf_version == 3
+ && a->dw_attr == DW_AT_data_member_location
+ && csize >= 4)
+ size += size_of_uleb128 (AT_unsigned (a));
+ else
+ size += csize;
+ }
break;
case dw_val_class_const_double:
size += 2 * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
case 2:
return DW_FORM_data2;
case 4:
+ /* In DWARF3 DW_AT_data_member_location with
+ DW_FORM_data4 or DW_FORM_data8 is a loclistptr, not
+ constant, so we need to use DW_FORM_udata if we need
+ a large constant. */
+ if (dwarf_version == 3 && a->dw_attr == DW_AT_data_member_location)
+ return DW_FORM_udata;
return DW_FORM_data4;
case 8:
+ if (dwarf_version == 3 && a->dw_attr == DW_AT_data_member_location)
+ return DW_FORM_udata;
return DW_FORM_data8;
default:
gcc_unreachable ();
break;
case dw_val_class_unsigned_const:
- dw2_asm_output_data (constant_size (AT_unsigned (a)),
- AT_unsigned (a), "%s", name);
+ {
+ int csize = constant_size (AT_unsigned (a));
+ if (dwarf_version == 3
+ && a->dw_attr == DW_AT_data_member_location
+ && csize >= 4)
+ dw2_asm_output_data_uleb128 (AT_unsigned (a), "%s", name);
+ else
+ dw2_asm_output_data (csize, AT_unsigned (a), "%s", name);
+ }
break;
case dw_val_class_const_double:
break;
case MEM:
+ {
+ rtx new_rtl = avoid_constant_pool_reference (rtl);
+ if (new_rtl != rtl)
+ {
+ mem_loc_result = mem_loc_descriptor (new_rtl, mode, mem_mode,
+ initialized);
+ if (mem_loc_result != NULL)
+ return mem_loc_result;
+ }
+ }
mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0),
get_address_mode (rtl), mode,
VAR_INIT_STATUS_INITIALIZED);
if (mem_loc_result == NULL)
mem_loc_result = tls_mem_loc_descriptor (rtl);
- if (mem_loc_result != 0)
+ if (mem_loc_result != NULL)
{
if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
|| GET_MODE_CLASS (mode) != MODE_INT)
new_loc_descr (DW_OP_deref_size,
GET_MODE_SIZE (mode), 0));
}
- else
- {
- rtx new_rtl = avoid_constant_pool_reference (rtl);
- if (new_rtl != rtl)
- return mem_loc_descriptor (new_rtl, mode, mem_mode, initialized);
- }
break;
case LO_SUM:
legitimate to make the Dwarf info refer to the whole register which
contains the given subreg. */
if (REG_P (SUBREG_REG (rtl)) && subreg_lowpart_p (rtl))
- loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
+ loc_result = loc_descriptor (SUBREG_REG (rtl),
+ GET_MODE (SUBREG_REG (rtl)), initialized);
else
goto do_default;
break;
dtype_die = lookup_type_die (dtype);
if (!dtype_die)
{
+ /* The descriptive type indirectly references TYPE if this is also the
+ case for TYPE itself. Do not deal with the circularity here. */
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)) = 1;
gen_type_die (dtype, context_die);
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)) = 0;
dtype_die = lookup_type_die (dtype);
gcc_assert (dtype_die);
}
ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
}
+ else if (insn
+ && NOTE_P (insn)
+ && NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL
+ && CODE_LABEL_NUMBER (insn) != -1)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
+ add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+ }
}
}
case OPT__output_pch_:
case OPT_fdiagnostics_show_location_:
case OPT_fdiagnostics_show_option:
+ case OPT_fverbose_asm:
case OPT____:
case OPT__sysroot_:
case OPT_nostdinc:
{
char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
struct var_loc_node *newloc;
- rtx next_real;
+ rtx next_real, next_note;
static const char *last_label;
static const char *last_postcall_label;
static bool last_in_cold_section_p;
+ static rtx expected_next_loc_note;
tree decl;
bool var_loc_p;
if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
return;
- next_real = next_real_insn (loc_note);
+ /* Optimize processing a large consecutive sequence of location
+ notes so we don't spend too much time in next_real_insn. If the
+ next insn is another location note, remember the next_real_insn
+ calculation for next time. */
+ next_real = cached_next_real_insn;
+ if (next_real)
+ {
+ if (expected_next_loc_note != loc_note)
+ next_real = NULL_RTX;
+ }
+
+ next_note = NEXT_INSN (loc_note);
+ if (! next_note
+ || INSN_DELETED_P (next_note)
+ || GET_CODE (next_note) != NOTE
+ || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION
+ && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION))
+ next_note = NULL_RTX;
+
+ if (! next_real)
+ next_real = next_real_insn (loc_note);
+
+ if (next_note)
+ {
+ expected_next_loc_note = next_note;
+ cached_next_real_insn = next_real;
+ }
+ else
+ cached_next_real_insn = NULL_RTX;
/* If there are no instructions which would be affected by this note,
don't do anything. */
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
macinfo_entry e;
+ /* Insert a dummy first entry to be able to optimize the whole
+ predefined macro block using DW_MACRO_GNU_transparent_include. */
+ if (VEC_empty (macinfo_entry, macinfo_table) && lineno == 0)
+ {
+ e.code = 0;
+ e.lineno = 0;
+ e.info = NULL;
+ VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+ }
e.code = DW_MACINFO_define;
e.lineno = lineno;
e.info = xstrdup (buffer);;
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
macinfo_entry e;
+ /* Insert a dummy first entry to be able to optimize the whole
+ predefined macro block using DW_MACRO_GNU_transparent_include. */
+ if (VEC_empty (macinfo_entry, macinfo_table) && lineno == 0)
+ {
+ e.code = 0;
+ e.lineno = 0;
+ e.info = NULL;
+ VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+ }
e.code = DW_MACINFO_undef;
e.lineno = lineno;
- e.info = xstrdup (buffer);;
+ e.info = xstrdup (buffer);
VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
}
}
+/* Routines to manipulate hash table of CUs. */
+
+static hashval_t
+htab_macinfo_hash (const void *of)
+{
+ const macinfo_entry *const entry =
+ (const macinfo_entry *) of;
+
+ return htab_hash_string (entry->info);
+}
+
+static int
+htab_macinfo_eq (const void *of1, const void *of2)
+{
+ const macinfo_entry *const entry1 = (const macinfo_entry *) of1;
+ const macinfo_entry *const entry2 = (const macinfo_entry *) of2;
+
+ return !strcmp (entry1->info, entry2->info);
+}
+
+/* Output a single .debug_macinfo entry. */
+
+static void
+output_macinfo_op (macinfo_entry *ref)
+{
+ int file_num;
+ size_t len;
+ struct indirect_string_node *node;
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ struct dwarf_file_data *fd;
+
+ switch (ref->code)
+ {
+ case DW_MACINFO_start_file:
+ fd = lookup_filename (ref->info);
+ if (fd->filename == ref->info)
+ fd->filename = ggc_strdup (fd->filename);
+ file_num = maybe_emit_file (fd);
+ dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
+ dw2_asm_output_data_uleb128 (ref->lineno,
+ "Included from line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
+ break;
+ case DW_MACINFO_end_file:
+ dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ len = strlen (ref->info) + 1;
+ if (!dwarf_strict
+ && len > DWARF_OFFSET_SIZE
+ && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+ && (debug_str_section->common.flags & SECTION_MERGE) != 0)
+ {
+ ref->code = ref->code == DW_MACINFO_define
+ ? DW_MACRO_GNU_define_indirect
+ : DW_MACRO_GNU_undef_indirect;
+ output_macinfo_op (ref);
+ return;
+ }
+ dw2_asm_output_data (1, ref->code,
+ ref->code == DW_MACINFO_define
+ ? "Define macro" : "Undefine macro");
+ dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_nstring (ref->info, -1, "The macro");
+ break;
+ case DW_MACRO_GNU_define_indirect:
+ case DW_MACRO_GNU_undef_indirect:
+ node = find_AT_string (ref->info);
+ if (node->form != DW_FORM_strp)
+ {
+ char label[32];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+ ++dw2_string_counter;
+ node->label = xstrdup (label);
+ node->form = DW_FORM_strp;
+ }
+ dw2_asm_output_data (1, ref->code,
+ ref->code == DW_MACRO_GNU_define_indirect
+ ? "Define macro indirect"
+ : "Undefine macro indirect");
+ dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+ debug_str_section, "The macro: \"%s\"",
+ ref->info);
+ break;
+ case DW_MACRO_GNU_transparent_include:
+ dw2_asm_output_data (1, ref->code, "Transparent include");
+ ASM_GENERATE_INTERNAL_LABEL (label,
+ DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
+ break;
+ default:
+ fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
+ ASM_COMMENT_START, (unsigned long) ref->code);
+ break;
+ }
+}
+
+/* Attempt to make a sequence of define/undef macinfo ops shareable with
+ other compilation unit .debug_macinfo sections. IDX is the first
+ index of a define/undef, return the number of ops that should be
+ emitted in a comdat .debug_macinfo section and emit
+ a DW_MACRO_GNU_transparent_include entry referencing it.
+ If the define/undef entry should be emitted normally, return 0. */
+
+static unsigned
+optimize_macinfo_range (unsigned int idx, VEC (macinfo_entry, gc) *files,
+ htab_t *macinfo_htab)
+{
+ macinfo_entry *first, *second, *cur, *inc;
+ char linebuf[sizeof (HOST_WIDE_INT) * 3 + 1];
+ unsigned char checksum[16];
+ struct md5_ctx ctx;
+ char *grp_name, *tail;
+ const char *base;
+ unsigned int i, count, encoded_filename_len, linebuf_len;
+ void **slot;
+
+ first = VEC_index (macinfo_entry, macinfo_table, idx);
+ second = VEC_index (macinfo_entry, macinfo_table, idx + 1);
+
+ /* Optimize only if there are at least two consecutive define/undef ops,
+ and either all of them are before first DW_MACINFO_start_file
+ with lineno 0 (i.e. predefined macro block), or all of them are
+ in some included header file. */
+ if (second->code != DW_MACINFO_define && second->code != DW_MACINFO_undef)
+ return 0;
+ if (VEC_empty (macinfo_entry, files))
+ {
+ if (first->lineno != 0 || second->lineno != 0)
+ return 0;
+ }
+ else if (first->lineno == 0)
+ return 0;
+
+ /* Find the last define/undef entry that can be grouped together
+ with first and at the same time compute md5 checksum of their
+ codes, linenumbers and strings. */
+ md5_init_ctx (&ctx);
+ for (i = idx; VEC_iterate (macinfo_entry, macinfo_table, i, cur); i++)
+ if (cur->code != DW_MACINFO_define && cur->code != DW_MACINFO_undef)
+ break;
+ else if (first->lineno == 0 && cur->lineno != 0)
+ break;
+ else
+ {
+ unsigned char code = cur->code;
+ md5_process_bytes (&code, 1, &ctx);
+ checksum_uleb128 (cur->lineno, &ctx);
+ md5_process_bytes (cur->info, strlen (cur->info) + 1, &ctx);
+ }
+ md5_finish_ctx (&ctx, checksum);
+ count = i - idx;
+
+ /* From the containing include filename (if any) pick up just
+ usable characters from its basename. */
+ if (first->lineno == 0)
+ base = "";
+ else
+ base = lbasename (VEC_last (macinfo_entry, files)->info);
+ for (encoded_filename_len = 0, i = 0; base[i]; i++)
+ if (ISIDNUM (base[i]) || base[i] == '.')
+ encoded_filename_len++;
+ /* Count . at the end. */
+ if (encoded_filename_len)
+ encoded_filename_len++;
+
+ sprintf (linebuf, HOST_WIDE_INT_PRINT_UNSIGNED, first->lineno);
+ linebuf_len = strlen (linebuf);
+
+ /* The group name format is: wmN.[<encoded filename>.]<lineno>.<md5sum> */
+ grp_name = XNEWVEC (char, 4 + encoded_filename_len + linebuf_len + 1
+ + 16 * 2 + 1);
+ memcpy (grp_name, DWARF_OFFSET_SIZE == 4 ? "wm4." : "wm8.", 4);
+ tail = grp_name + 4;
+ if (encoded_filename_len)
+ {
+ for (i = 0; base[i]; i++)
+ if (ISIDNUM (base[i]) || base[i] == '.')
+ *tail++ = base[i];
+ *tail++ = '.';
+ }
+ memcpy (tail, linebuf, linebuf_len);
+ tail += linebuf_len;
+ *tail++ = '.';
+ for (i = 0; i < 16; i++)
+ sprintf (tail + i * 2, "%02x", checksum[i] & 0xff);
+
+ /* Construct a macinfo_entry for DW_MACRO_GNU_transparent_include
+ in the empty vector entry before the first define/undef. */
+ inc = VEC_index (macinfo_entry, macinfo_table, idx - 1);
+ inc->code = DW_MACRO_GNU_transparent_include;
+ inc->lineno = 0;
+ inc->info = grp_name;
+ if (*macinfo_htab == NULL)
+ *macinfo_htab = htab_create (10, htab_macinfo_hash, htab_macinfo_eq, NULL);
+ /* Avoid emitting duplicates. */
+ slot = htab_find_slot (*macinfo_htab, inc, INSERT);
+ if (*slot != NULL)
+ {
+ free (CONST_CAST (char *, inc->info));
+ inc->code = 0;
+ inc->info = NULL;
+ /* If such an entry has been used before, just emit
+ a DW_MACRO_GNU_transparent_include op. */
+ inc = (macinfo_entry *) *slot;
+ output_macinfo_op (inc);
+ /* And clear all macinfo_entry in the range to avoid emitting them
+ in the second pass. */
+ for (i = idx;
+ VEC_iterate (macinfo_entry, macinfo_table, i, cur)
+ && i < idx + count;
+ i++)
+ {
+ cur->code = 0;
+ free (CONST_CAST (char *, cur->info));
+ cur->info = NULL;
+ }
+ }
+ else
+ {
+ *slot = inc;
+ inc->lineno = htab_elements (*macinfo_htab);
+ output_macinfo_op (inc);
+ }
+ return count;
+}
+
+/* Output macinfo section(s). */
+
static void
output_macinfo (void)
{
unsigned i;
unsigned long length = VEC_length (macinfo_entry, macinfo_table);
macinfo_entry *ref;
+ VEC (macinfo_entry, gc) *files = NULL;
+ htab_t macinfo_htab = NULL;
if (! length)
return;
+ /* output_macinfo* uses these interchangeably. */
+ gcc_assert ((int) DW_MACINFO_define == (int) DW_MACRO_GNU_define
+ && (int) DW_MACINFO_undef == (int) DW_MACRO_GNU_undef
+ && (int) DW_MACINFO_start_file == (int) DW_MACRO_GNU_start_file
+ && (int) DW_MACINFO_end_file == (int) DW_MACRO_GNU_end_file);
+
+ /* For .debug_macro emit the section header. */
+ if (!dwarf_strict)
+ {
+ dw2_asm_output_data (2, 4, "DWARF macro version number");
+ if (DWARF_OFFSET_SIZE == 8)
+ dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
+ else
+ dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_section_label,
+ debug_line_section, NULL);
+ }
+
+ /* In the first loop, it emits the primary .debug_macinfo section
+ and after each emitted op the macinfo_entry is cleared.
+ If a longer range of define/undef ops can be optimized using
+ DW_MACRO_GNU_transparent_include, the
+ DW_MACRO_GNU_transparent_include op is emitted and kept in
+ the vector before the first define/undef in the range and the
+ whole range of define/undef ops is not emitted and kept. */
for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
{
switch (ref->code)
{
- case DW_MACINFO_start_file:
+ case DW_MACINFO_start_file:
+ VEC_safe_push (macinfo_entry, gc, files, ref);
+ break;
+ case DW_MACINFO_end_file:
+ if (!VEC_empty (macinfo_entry, files))
{
- int file_num = maybe_emit_file (lookup_filename (ref->info));
- dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
- dw2_asm_output_data_uleb128
- (ref->lineno, "Included from line number %lu",
- (unsigned long)ref->lineno);
- dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
+ macinfo_entry *file = VEC_last (macinfo_entry, files);
+ free (CONST_CAST (char *, file->info));
+ VEC_pop (macinfo_entry, files);
}
- break;
- case DW_MACINFO_end_file:
- dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
- break;
- case DW_MACINFO_define:
- dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
- dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
- (unsigned long)ref->lineno);
- dw2_asm_output_nstring (ref->info, -1, "The macro");
- break;
- case DW_MACINFO_undef:
- dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
- dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
- (unsigned long)ref->lineno);
- dw2_asm_output_nstring (ref->info, -1, "The macro");
- break;
- default:
- fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
- ASM_COMMENT_START, (unsigned long)ref->code);
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ if (!dwarf_strict
+ && HAVE_COMDAT_GROUP
+ && VEC_length (macinfo_entry, files) != 1
+ && i > 0
+ && i + 1 < length
+ && VEC_index (macinfo_entry, macinfo_table, i - 1)->code == 0)
+ {
+ unsigned count = optimize_macinfo_range (i, files, &macinfo_htab);
+ if (count)
+ {
+ i += count - 1;
+ continue;
+ }
+ }
+ break;
+ case 0:
+ /* A dummy entry may be inserted at the beginning to be able
+ to optimize the whole block of predefined macros. */
+ if (i == 0)
+ continue;
+ default:
break;
}
+ output_macinfo_op (ref);
+ /* For DW_MACINFO_start_file ref->info has been copied into files
+ vector. */
+ if (ref->code != DW_MACINFO_start_file)
+ free (CONST_CAST (char *, ref->info));
+ ref->info = NULL;
+ ref->code = 0;
}
+
+ if (macinfo_htab == NULL)
+ return;
+
+ htab_delete (macinfo_htab);
+
+ /* If any DW_MACRO_GNU_transparent_include were used, on those
+ DW_MACRO_GNU_transparent_include entries terminate the
+ current chain and switch to a new comdat .debug_macinfo
+ section and emit the define/undef entries within it. */
+ for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
+ switch (ref->code)
+ {
+ case 0:
+ continue;
+ case DW_MACRO_GNU_transparent_include:
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ tree comdat_key = get_identifier (ref->info);
+ /* Terminate the previous .debug_macinfo section. */
+ dw2_asm_output_data (1, 0, "End compilation unit");
+ targetm.asm_out.named_section (DEBUG_MACRO_SECTION,
+ SECTION_DEBUG
+ | SECTION_LINKONCE,
+ comdat_key);
+ ASM_GENERATE_INTERNAL_LABEL (label,
+ DEBUG_MACRO_SECTION_LABEL,
+ ref->lineno);
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+ ref->code = 0;
+ free (CONST_CAST (char *, ref->info));
+ ref->info = NULL;
+ dw2_asm_output_data (2, 4, "DWARF macro version number");
+ if (DWARF_OFFSET_SIZE == 8)
+ dw2_asm_output_data (1, 1, "Flags: 64-bit");
+ else
+ dw2_asm_output_data (1, 0, "Flags: 32-bit");
+ }
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ output_macinfo_op (ref);
+ ref->code = 0;
+ free (CONST_CAST (char *, ref->info));
+ ref->info = NULL;
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
/* Set up for Dwarf output at the start of compilation. */
SECTION_DEBUG, NULL);
debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
SECTION_DEBUG, NULL);
- debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION,
+ debug_macinfo_section = get_section (dwarf_strict
+ ? DEBUG_MACINFO_SECTION
+ : DEBUG_MACRO_SECTION,
SECTION_DEBUG, NULL);
debug_line_section = get_section (DEBUG_LINE_SECTION,
SECTION_DEBUG, NULL);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
DEBUG_RANGES_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
- DEBUG_MACINFO_SECTION_LABEL, 0);
+ dwarf_strict
+ ? DEBUG_MACINFO_SECTION_LABEL
+ : DEBUG_MACRO_SECTION_LABEL, 0);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
}
break;
case dw_val_class_loc:
- if (!resolve_addr_in_expr (AT_loc (a)))
- {
- remove_AT (die, a->dw_attr);
- ix--;
- }
- else
- mark_base_types (AT_loc (a));
+ {
+ dw_loc_descr_ref l = AT_loc (a);
+ /* For -gdwarf-2 don't attempt to optimize
+ DW_AT_data_member_location containing
+ DW_OP_plus_uconst - older consumers might
+ rely on it being that op instead of a more complex,
+ but shorter, location description. */
+ if ((dwarf_version > 2
+ || a->dw_attr != DW_AT_data_member_location
+ || l == NULL
+ || l->dw_loc_opc != DW_OP_plus_uconst
+ || l->dw_loc_next != NULL)
+ && !resolve_addr_in_expr (l))
+ {
+ remove_AT (die, a->dw_attr);
+ ix--;
+ }
+ else
+ mark_base_types (l);
+ }
break;
case dw_val_class_addr:
if (a->dw_attr == DW_AT_const_value
debug_line_section_label);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- add_AT_macptr (comp_unit_die (), DW_AT_macro_info, macinfo_section_label);
+ add_AT_macptr (comp_unit_die (),
+ dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+ macinfo_section_label);
if (have_location_lists)
optimize_location_lists (comp_unit_die ());
output_ranges ();
}
+ /* Have to end the macro section. */
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ switch_to_section (debug_macinfo_section);
+ ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+ if (!VEC_empty (macinfo_entry, macinfo_table))
+ output_macinfo ();
+ dw2_asm_output_data (1, 0, "End compilation unit");
+ }
+
/* Output the source line correspondence table. We must do this
even if there is no line information. Otherwise, on an empty
translation unit, we will generate a present, but empty,
if (! DWARF2_ASM_LINE_DEBUG_INFO)
output_line_info ();
- /* Have to end the macro section. */
- if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- {
- switch_to_section (debug_macinfo_section);
- ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
- if (!VEC_empty (macinfo_entry, macinfo_table))
- output_macinfo ();
- dw2_asm_output_data (1, 0, "End compilation unit");
- }
-
/* If we emitted any DW_FORM_strp form attribute, output the string
table too. */
if (debug_str_hash)