===================================================================
@@ -190,7 +190,6 @@ enum dwarf_form
DW_FORM_flag_present = 0x19,
DW_FORM_ref_sig8 = 0x20,
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
- DW_FORM_GNU_ref_index = 0x1f00,
DW_FORM_GNU_addr_index = 0x1f01,
DW_FORM_GNU_str_index = 0x1f02
};
@@ -375,7 +374,7 @@ enum dwarf_attribute
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
DW_AT_GNU_dwo_name = 0x2130,
DW_AT_GNU_dwo_id = 0x2131,
- DW_AT_GNU_ref_base = 0x2132,
+ DW_AT_GNU_ranges_base = 0x2132,
DW_AT_GNU_addr_base = 0x2133,
DW_AT_GNU_pubnames = 0x2134,
DW_AT_GNU_pubtypes = 0x2135,
@@ -578,6 +577,9 @@ enum dwarf_location_atom
DW_OP_GNU_reinterpret = 0xf9,
/* The GNU parameter ref extension. */
DW_OP_GNU_parameter_ref = 0xfa,
+ /* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
+ DW_OP_GNU_addr_index = 0xfb,
+ DW_OP_GNU_const_index = 0xfc,
/* HP extensions. */
DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */
DW_OP_HP_is_value = 0xe1,
@@ -829,6 +831,17 @@ enum dwarf_call_frame_info
DW_CFA_GNU_negative_offset_extended = 0x2f
};
+/* Type codes for location list entries.
+ Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
+
+enum dwarf_location_list_entry_type
+ {
+ DW_LLE_end_of_list_entry = 0,
+ DW_LLE_base_address_selection_entry = 1,
+ DW_LLE_start_end_entry = 2,
+ DW_LLE_start_length_entry = 3
+ };
+
#define DW_CIE_ID 0xffffffff
#define DW64_CIE_ID 0xffffffffffffffffULL
#define DW_CIE_VERSION 1
===================================================================
@@ -4952,6 +4952,14 @@ it reasonable to use the optimizer for p
The following options are useful when GCC is generated with the
capability for more than one debugging format.
+@item -gsplit-dwarf
+@opindex gsplit-dwarf
+Separate as much dwarf debugging information as possible into a
+separate output file with the extension .dwo. This option allows
+the build system to avoid linking files with debug information. To
+be useful, this option requires a debugger capable of reading .dwo
+files.
+
@item -ggdb
@opindex ggdb
Produce debugging information for use by GDB@. This means to use the
===================================================================
@@ -267,6 +267,7 @@ static const char *compare_debug_dump_op
static const char *compare_debug_self_opt_spec_function (int, const char **);
static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
static const char *pass_through_libs_spec_func (int, const char **);
+static const char *replace_extension_spec_func (int, const char **);
/* The Specs Language
@@ -446,7 +447,7 @@ ignored. White space may also appear an
colon in these constructs, except between . or * and the corresponding
word.
-The -O, -f, -m, and -W switches are handled specifically in these
+The -O, -f, -g, -m, and -W switches are handled specifically in these
constructs. If another value of -O or the negated form of a -f, -m, or
-W switch is found later in the command line, the earlier switch
value is ignored, except with {S*} where S is just one letter; this
@@ -479,7 +480,14 @@ proper position among the other output f
/* config.h can define ASM_FINAL_SPEC to run a post processor after
the assembler has run. */
#ifndef ASM_FINAL_SPEC
-#define ASM_FINAL_SPEC ""
+#define ASM_FINAL_SPEC \
+ "%{gsplit-dwarf: \n\
+ objcopy --extract-dwo \
+ %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+ %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
+ objcopy --strip-dwo \
+ %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+ }"
#endif
/* config.h can define CPP_SPEC to provide extra args to the C preprocessor
@@ -1276,6 +1284,7 @@ static const struct spec_function static
{ "compare-debug-self-opt", compare_debug_self_opt_spec_function },
{ "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
{ "pass-through-libs", pass_through_libs_spec_func },
+ { "replace-extension", replace_extension_spec_func },
#ifdef EXTRA_SPEC_FUNCTIONS
EXTRA_SPEC_FUNCTIONS
#endif
@@ -5783,7 +5792,7 @@ process_brace_body (const char *p, const
on the command line. PREFIX_LENGTH is the length of XXX in an {XXX*}
spec, or -1 if either exact match or %* is used.
- A -O switch is obsoleted by a later -O switch. A -f, -m, or -W switch
+ A -O switch is obsoleted by a later -O switch. A -f, -g, -m, or -W switch
whose value does not begin with "no-" is obsoleted by the same value
with the "no-", similarly for a switch with the "no-" prefix. */
@@ -5820,7 +5829,7 @@ check_live_switch (int switchnum, int pr
}
break;
- case 'W': case 'f': case 'm':
+ case 'W': case 'f': case 'm': case 'g':
if (! strncmp (name + 1, "no-", 3))
{
/* We have Xno-YYY, search for XYYY. */
@@ -8394,3 +8403,27 @@ pass_through_libs_spec_func (int argc, c
}
return prepended;
}
+
+/* %:replace-extension spec function. Replaces the extension of the
+ first argument with the second argument. */
+
+const char *
+replace_extension_spec_func (int argc, const char **argv)
+{
+ char *name;
+ char *p;
+ char *result;
+
+ if (argc != 2)
+ fatal_error ("too few arguments to %%:replace-extension");
+
+ name = xstrdup (argv[0]);
+ p = strrchr (name, '.');
+ if (p != NULL)
+ *p = '\0';
+
+ result = concat (name, argv[1], NULL);
+
+ free (name);
+ return result;
+}
===================================================================
@@ -153,14 +153,19 @@ static GTY(()) VEC(tree,gc) *decl_scope_
/* Pointers to various DWARF2 sections. */
static GTY(()) section *debug_info_section;
+static GTY(()) section *debug_skeleton_info_section;
static GTY(()) section *debug_abbrev_section;
+static GTY(()) section *debug_skeleton_abbrev_section;
static GTY(()) section *debug_aranges_section;
+static GTY(()) section *debug_addr_section;
static GTY(()) section *debug_macinfo_section;
static GTY(()) section *debug_line_section;
+static GTY(()) section *debug_skeleton_line_section;
static GTY(()) section *debug_loc_section;
static GTY(()) section *debug_pubnames_section;
static GTY(()) section *debug_pubtypes_section;
static GTY(()) section *debug_str_section;
+static GTY(()) section *debug_str_offsets_section;
static GTY(()) section *debug_ranges_section;
static GTY(()) section *debug_frame_section;
@@ -203,6 +208,7 @@ struct GTY(()) indirect_string_node {
unsigned int refcount;
enum dwarf_form form;
char *label;
+ unsigned int index;
};
static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
@@ -1214,7 +1220,8 @@ DEF_VEC_ALLOC_P(dw_die_ref,heap);
their entire life. */
typedef struct GTY(()) dw_loc_list_struct {
dw_loc_list_ref dw_loc_next;
- const char *begin; /* Label for begin address of range */
+ const char *begin; /* Label and index for begin address of range */
+ unsigned int begin_index;
const char *end; /* Label for end address of range */
char *ll_symbol; /* Label for beginning of location list.
Only on head of list */
@@ -1591,8 +1598,10 @@ new_loc_descr (enum dwarf_location_atom
descr->dw_loc_opc = op;
descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
+ descr->dw_loc_oprnd1.val_index = -1U;
descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
+ descr->dw_loc_oprnd2.val_index = -1U;
descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
return descr;
@@ -1796,6 +1805,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
case DW_OP_addr:
size += DWARF2_ADDR_SIZE;
break;
+ case DW_OP_GNU_addr_index:
+ case DW_OP_GNU_const_index:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index);
+ break;
case DW_OP_const1u:
case DW_OP_const1s:
size += 1;
@@ -2232,6 +2245,12 @@ output_loc_operands (dw_loc_descr_ref lo
}
break;
+ case DW_OP_GNU_addr_index:
+ case DW_OP_GNU_const_index:
+ dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index,
+ "(index into .debug_addr)");
+ break;
+
case DW_OP_GNU_implicit_pointer:
{
char label[MAX_ARTIFICIAL_LABEL_BYTES
@@ -2407,6 +2426,8 @@ output_loc_operands_raw (dw_loc_descr_re
switch (loc->dw_loc_opc)
{
case DW_OP_addr:
+ case DW_OP_GNU_addr_index:
+ case DW_OP_GNU_const_index:
case DW_OP_implicit_value:
/* We cannot output addresses in .cfi_escape, only bytes. */
gcc_unreachable ();
@@ -2590,6 +2611,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOS
{
head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
head->dw_loc_oprnd1.val_class = dw_val_class_const;
+ head->dw_loc_oprnd1.val_index = -1U;
tmp = new_loc_descr (DW_OP_deref, 0, 0);
add_loc_descr (&head, tmp);
if (offset != 0)
@@ -3217,6 +3239,8 @@ static tree decl_ultimate_origin (const_
static tree decl_class_context (tree);
static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
static inline enum dw_val_class AT_class (dw_attr_ref);
+static inline unsigned int AT_index (dw_attr_ref);
+static inline void set_AT_index (dw_attr_ref, unsigned int);
static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
static inline unsigned AT_flag (dw_attr_ref);
static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
@@ -3244,15 +3268,18 @@ static inline dw_loc_descr_ref AT_loc (d
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_ref);
-static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
+static unsigned int add_addr_table_entry (dw_attr_node *);
+static void remove_addr_table_entry (unsigned int);
+static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
static inline rtx AT_addr (dw_attr_ref);
-static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *,
+ bool);
static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
unsigned HOST_WIDE_INT);
static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
- unsigned long);
+ unsigned long, bool);
static inline const char *AT_lbl (dw_attr_ref);
static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
static const char *get_AT_low_pc (dw_die_ref);
@@ -3347,6 +3374,7 @@ static unsigned long size_of_aranges (vo
static enum dwarf_form value_format (dw_attr_ref);
static void output_value_format (dw_attr_ref);
static void output_abbrev_section (void);
+static void output_die_abbrevs (unsigned long, dw_die_ref);
static void output_die_symbol (dw_die_ref);
static void output_die (dw_die_ref);
static void output_compilation_unit_header (void);
@@ -3362,10 +3390,10 @@ static void output_aranges (unsigned lon
static unsigned int add_ranges_num (int);
static unsigned int add_ranges (const_tree);
static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
- bool *);
+ bool *, bool);
static void output_ranges (void);
static dw_line_info_table *new_line_info_table (void);
-static void output_line_info (void);
+static void output_line_info (bool);
static void output_file_names (void);
static dw_die_ref base_type_die (tree);
static int is_base_type (tree);
@@ -3504,36 +3532,124 @@ static bool generic_type_p (tree);
static void schedule_generic_params_dies_gen (tree t);
static void gen_scheduled_generic_parms_dies (void);
+/* Return the operator to use for an address of a variable.
+ DTPREL is true for thread-local variables whose address
+ is really an offset relative to the TLS pointer, which
+ will need link-time relocation, but will not need relocation
+ by the DWARF consumer. For those, we use DW_OP_const*.
+ For regular variables, which need both link-time relocation
+ and consumer-level relocation (e.g., to account for
+ shared objects loaded at a random address), we use
+ DW_OP_addr*. */
+
+static inline enum dwarf_location_atom dw_addr_op (bool dtprel)
+{
+ if (dtprel)
+ return (dwarf_split_debug_info ? DW_OP_GNU_const_index
+ : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
+ else
+ return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr);
+}
+
+/* Return a pointer to a newly allocated address location description. If
+ dwarf_split_debug_info is true, then record the address with the appropriate
+ relocation. */
+static inline dw_loc_descr_ref
+new_addr_loc_descr (rtx addr, int dtprel)
+{
+ dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
+
+ ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
+ ref->dw_loc_oprnd1.val_index = -1U;
+ ref->dw_loc_oprnd1.v.val_addr = addr;
+ ref->dtprel = dtprel;
+ if (dwarf_split_debug_info)
+ {
+ dw_attr_node attr;
+
+ attr.dw_attr = DW_AT_location;
+ attr.dw_attr_val.val_class = (dtprel
+ ? dw_val_class_loc : dw_val_class_addr);
+ attr.dw_attr_val.val_index = -1U;
+ attr.dw_attr_val.v.val_addr = addr;
+
+ ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr);
+ }
+ return ref;
+}
+
/* Section names used to hold DWARF debugging information. */
+
#ifndef DEBUG_INFO_SECTION
#define DEBUG_INFO_SECTION ".debug_info"
#endif
+#ifndef DEBUG_DWO_INFO_SECTION
+#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
+#endif
#ifndef DEBUG_ABBREV_SECTION
#define DEBUG_ABBREV_SECTION ".debug_abbrev"
#endif
+#ifndef DEBUG_DWO_ABBREV_SECTION
+#define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo"
+#endif
#ifndef DEBUG_ARANGES_SECTION
#define DEBUG_ARANGES_SECTION ".debug_aranges"
#endif
+#ifndef DEBUG_ADDR_SECTION
+#define DEBUG_ADDR_SECTION ".debug_addr"
+#endif
+#ifndef DEBUG_NORM_MACINFO_SECTION
+#define DEBUG_NORM_MACINFO_SECTION ".debug_macinfo"
+#endif
+#ifndef DEBUG_DWO_MACINFO_SECTION
+#define DEBUG_DWO_MACINFO_SECTION ".debug_macinfo.dwo"
+#endif
#ifndef DEBUG_MACINFO_SECTION
-#define DEBUG_MACINFO_SECTION ".debug_macinfo"
+#define DEBUG_MACINFO_SECTION \
+ (!dwarf_split_debug_info \
+ ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION))
+#endif
+#ifndef DEBUG_NORM_MACRO_SECTION
+#define DEBUG_NORM_MACRO_SECTION ".debug_macro"
+#endif
+#ifndef DEBUG_DWO_MACRO_SECTION
+#define DEBUG_DWO_MACRO_SECTION ".debug_macro.dwo"
#endif
#ifndef DEBUG_MACRO_SECTION
-#define DEBUG_MACRO_SECTION ".debug_macro"
+#define DEBUG_MACRO_SECTION \
+ (!dwarf_split_debug_info \
+ ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION))
#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
+#ifndef DEBUG_DWO_LINE_SECTION
+#define DEBUG_DWO_LINE_SECTION ".debug_line.dwo"
+#endif
#ifndef DEBUG_LOC_SECTION
#define DEBUG_LOC_SECTION ".debug_loc"
#endif
+#ifndef DEBUG_DWO_LOC_SECTION
+#define DEBUG_DWO_LOC_SECTION ".debug_loc.dwo"
+#endif
#ifndef DEBUG_PUBNAMES_SECTION
#define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
#endif
#ifndef DEBUG_PUBTYPES_SECTION
#define DEBUG_PUBTYPES_SECTION ".debug_pubtypes"
#endif
+#define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets"
+#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
+#ifndef DEBUG_STR_OFFSETS_SECTION
+#define DEBUG_STR_OFFSETS_SECTION \
+ (!dwarf_split_debug_info \
+ ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION))
+#endif
+#define DEBUG_DWO_STR_SECTION ".debug_str.dwo"
+#define DEBUG_NORM_STR_SECTION ".debug_str"
#ifndef DEBUG_STR_SECTION
-#define DEBUG_STR_SECTION ".debug_str"
+#define DEBUG_STR_SECTION \
+ (!dwarf_split_debug_info ? (DEBUG_NORM_STR_SECTION) : (DEBUG_DWO_STR_SECTION))
#endif
#ifndef DEBUG_RANGES_SECTION
#define DEBUG_RANGES_SECTION ".debug_ranges"
@@ -3544,11 +3660,17 @@ static void gen_scheduled_generic_parms_
#define TEXT_SECTION_NAME ".text"
#endif
+/* Section flags for .debug_macinfo/.debug_macro section. */
+#define DEBUG_MACRO_SECTION_FLAGS \
+ (dwarf_split_debug_info ? SECTION_DEBUG | SECTION_EXCLUDE : SECTION_DEBUG)
+
/* Section flags for .debug_str section. */
#define DEBUG_STR_SECTION_FLAGS \
- (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \
- ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1 \
- : SECTION_DEBUG)
+ (dwarf_split_debug_info \
+ ? SECTION_DEBUG | SECTION_EXCLUDE \
+ : (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \
+ ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1 \
+ : SECTION_DEBUG))
/* Labels we insert at beginning sections we can reference instead of
the section names themselves. */
@@ -3568,12 +3690,24 @@ static void gen_scheduled_generic_parms_
#ifndef DEBUG_LINE_SECTION_LABEL
#define DEBUG_LINE_SECTION_LABEL "Ldebug_line"
#endif
+#ifndef DEBUG_SKELETON_LINE_SECTION_LABEL
+#define DEBUG_SKELETON_LINE_SECTION_LABEL "Lskeleton_debug_line"
+#endif
#ifndef DEBUG_INFO_SECTION_LABEL
#define DEBUG_INFO_SECTION_LABEL "Ldebug_info"
#endif
+#ifndef DEBUG_SKELETON_INFO_SECTION_LABEL
+#define DEBUG_SKELETON_INFO_SECTION_LABEL "Lskeleton_debug_info"
+#endif
#ifndef DEBUG_ABBREV_SECTION_LABEL
#define DEBUG_ABBREV_SECTION_LABEL "Ldebug_abbrev"
#endif
+#ifndef DEBUG_SKELETON_ABBREV_SECTION_LABEL
+#define DEBUG_SKELETON_ABBREV_SECTION_LABEL "Lskeleton_debug_abbrev"
+#endif
+#ifndef DEBUG_ADDR_SECTION_LABEL
+#define DEBUG_ADDR_SECTION_LABEL "Ldebug_addr"
+#endif
#ifndef DEBUG_LOC_SECTION_LABEL
#define DEBUG_LOC_SECTION_LABEL "Ldebug_loc"
#endif
@@ -3587,6 +3721,9 @@ static void gen_scheduled_generic_parms_
#define DEBUG_MACRO_SECTION_LABEL "Ldebug_macro"
#endif
+#define SKELETON_COMP_DIE_ABBREV 1
+#define SKELETON_TYPE_DIE_ABBREV 2
+
/* Definitions of defaults for formats and names of various special
(artificial) labels which may be generated within this file (when the -g
@@ -3600,7 +3737,11 @@ static char cold_text_section_label[MAX_
static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_pubnames_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_pubtypes_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
@@ -4271,6 +4412,31 @@ AT_class (dw_attr_ref a)
return a->dw_attr_val.val_class;
}
+/* Return the index for any attribute that will be referenced with a
+ DW_FORM_GNU_addr_index. Strings have their indices handled differently to
+ account for reference counting pruning. */
+
+static inline unsigned int
+AT_index (dw_attr_ref a)
+{
+ if (AT_class (a) == dw_val_class_str)
+ return a->dw_attr_val.v.val_str->index;
+ else
+ return a->dw_attr_val.val_index;
+}
+
+/* Set the index for any attribute that will be referenced with a
+ DW_FORM_GNU_addr_index. */
+
+static inline void
+set_AT_index (dw_attr_ref a, unsigned int index)
+{
+ if (AT_class (a) == dw_val_class_str)
+ a->dw_attr_val.v.val_str->index = index;
+ else
+ a->dw_attr_val.val_index = index;
+}
+
/* Add a flag value attribute to a DIE. */
static inline void
@@ -4280,6 +4446,7 @@ add_AT_flag (dw_die_ref die, enum dwarf_
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_flag;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_flag = flag;
add_dwarf_attr (die, &attr);
}
@@ -4300,6 +4467,7 @@ add_AT_int (dw_die_ref die, enum dwarf_a
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_const;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_int = int_val;
add_dwarf_attr (die, &attr);
}
@@ -4321,6 +4489,7 @@ add_AT_unsigned (dw_die_ref die, enum dw
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_unsigned = unsigned_val;
add_dwarf_attr (die, &attr);
}
@@ -4342,6 +4511,7 @@ add_AT_double (dw_die_ref die, enum dwar
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_const_double;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_double.high = high;
attr.dw_attr_val.v.val_double.low = low;
add_dwarf_attr (die, &attr);
@@ -4357,6 +4527,7 @@ add_AT_vec (dw_die_ref die, enum dwarf_a
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_vec;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_vec.length = length;
attr.dw_attr_val.v.val_vec.elt_size = elt_size;
attr.dw_attr_val.v.val_vec.array = array;
@@ -4373,6 +4544,7 @@ add_AT_data8 (dw_die_ref die, enum dwarf
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_data8;
+ attr.dw_attr_val.val_index = -1U;
memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
add_dwarf_attr (die, &attr);
}
@@ -4431,6 +4603,7 @@ add_AT_string (dw_die_ref die, enum dwar
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_str;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_str = node;
add_dwarf_attr (die, &attr);
}
@@ -4442,12 +4615,20 @@ AT_string (dw_attr_ref a)
return a->dw_attr_val.v.val_str->str;
}
+/* A vector for a table of strings in the form DW_FORM_GNU_index_str. */
+
+typedef struct indirect_string_node indirect_string_node;
+DEF_VEC_O(indirect_string_node);
+DEF_VEC_ALLOC_O(indirect_string_node, gc);
+static GTY (()) VEC (indirect_string_node, gc) *index_string_table;
+
/* Find out whether a string should be output inline in DIE
or out-of-line in .debug_str section. */
static enum dwarf_form
AT_string_form (dw_attr_ref a)
{
+ static unsigned int index_string_count = 0;
struct indirect_string_node *node;
unsigned int len;
char label[32];
@@ -4477,7 +4658,17 @@ AT_string_form (dw_attr_ref a)
++dw2_string_counter;
node->label = xstrdup (label);
- return node->form = DW_FORM_strp;
+ if (!dwarf_split_debug_info)
+ node->form = DW_FORM_strp;
+ else
+ {
+ node->form = DW_FORM_GNU_str_index;
+ set_AT_index (a, index_string_count);
+ index_string_count++;
+ VEC_safe_push (indirect_string_node, gc, index_string_table, node);
+ }
+
+ return node->form;
}
/* Add a DIE reference attribute value to a DIE. */
@@ -4498,6 +4689,7 @@ add_AT_die_ref (dw_die_ref die, enum dwa
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_die_ref;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_die_ref.die = targ_die;
attr.dw_attr_val.v.val_die_ref.external = 0;
add_dwarf_attr (die, &attr);
@@ -4546,6 +4738,7 @@ add_AT_fde_ref (dw_die_ref die, enum dwa
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_fde_ref;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_fde_index = targ_fde;
add_dwarf_attr (die, &attr);
}
@@ -4559,6 +4752,7 @@ add_AT_loc (dw_die_ref die, enum dwarf_a
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_loc;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_loc = loc;
add_dwarf_attr (die, &attr);
}
@@ -4577,6 +4771,7 @@ add_AT_loc_list (dw_die_ref die, enum dw
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_loc_list;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_loc_list = loc_list;
add_dwarf_attr (die, &attr);
have_location_lists = true;
@@ -4596,17 +4791,64 @@ AT_loc_list_ptr (dw_attr_ref a)
return &a->dw_attr_val.v.val_loc_list;
}
+/* A table of entries into the .debug_addr section. */
+
+static GTY (()) VEC (dw_attr_node,gc) * addr_index_table;
+
+static unsigned int
+add_addr_table_entry (dw_attr_node *attr)
+{
+ gcc_assert (dwarf_split_debug_info);
+
+ VEC_safe_push (dw_attr_node, gc, addr_index_table, attr);
+ return VEC_length (dw_attr_node, addr_index_table) - 1;
+}
+
+/* Remove an entry from the addr table. Since we have already numbered
+ all the entries, the best we can do here is null it out. */
+
+static void
+remove_addr_table_entry (unsigned int i)
+{
+ dw_attr_node *attr;
+
+ gcc_assert (dwarf_split_debug_info);
+ gcc_assert (i < VEC_length (dw_attr_node, addr_index_table));
+
+ attr = VEC_index (dw_attr_node, addr_index_table, i);
+ attr->dw_attr = (enum dwarf_attribute) 0;
+}
+
+/* Given a location list, remove all addresses it refers to from the
+ address_table. */
+
+static void
+remove_loc_list_addr_table_entries (dw_loc_list_ref loc)
+{
+ dw_loc_descr_ref descr;
+
+ gcc_assert (loc->replaced);
+
+ for (descr = loc->expr; descr; descr = descr->dw_loc_next)
+ if (descr->dw_loc_oprnd1.val_index != -1U)
+ remove_addr_table_entry (descr->dw_loc_oprnd1.val_index);
+}
+
/* Add an address constant attribute value to a DIE. */
static inline void
-add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
+add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr,
+ bool force_direct)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_addr;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_addr = addr;
add_dwarf_attr (die, &attr);
+ if (dwarf_split_debug_info && !force_direct)
+ set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
}
/* Get the RTX from to an address DIE attribute. */
@@ -4628,6 +4870,7 @@ add_AT_file (dw_die_ref die, enum dwarf_
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_file;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_file = fd;
add_dwarf_attr (die, &attr);
}
@@ -4651,6 +4894,7 @@ add_AT_vms_delta (dw_die_ref die, enum d
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_vms_delta;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
add_dwarf_attr (die, &attr);
@@ -4659,14 +4903,18 @@ add_AT_vms_delta (dw_die_ref die, enum d
/* Add a label identifier attribute value to a DIE. */
static inline void
-add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
+add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *lbl_id, bool force_direct)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
add_dwarf_attr (die, &attr);
+ if (dwarf_split_debug_info && !force_direct)
+ set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
}
/* Add a section offset attribute value to a DIE, an offset into the
@@ -4680,6 +4928,7 @@ add_AT_lineptr (dw_die_ref die, enum dwa
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_lineptr;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
add_dwarf_attr (die, &attr);
}
@@ -4695,6 +4944,7 @@ add_AT_macptr (dw_die_ref die, enum dwar
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_macptr;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
add_dwarf_attr (die, &attr);
}
@@ -4709,20 +4959,25 @@ add_AT_offset (dw_die_ref die, enum dwar
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_offset;
+ attr.dw_attr_val.val_index = -1U;
attr.dw_attr_val.v.val_offset = offset;
add_dwarf_attr (die, &attr);
}
-/* Add an range_list attribute value to a DIE. */
+/* Add a range_list attribute value to a DIE. */
static void
add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
- long unsigned int offset)
+ long unsigned int offset, bool force_direct)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_range_list;
+ /* This is a bit of a misnomer--the offset isn't an index, but we need to
+ save force_direct for output. */
+ attr.dw_attr_val.val_index
+ = (dwarf_split_debug_info && !force_direct) ? offset : -1U;
attr.dw_attr_val.v.val_offset = offset;
add_dwarf_attr (die, &attr);
}
@@ -7716,6 +7971,7 @@ size_of_die (dw_die_ref die)
unsigned long size = 0;
dw_attr_ref a;
unsigned ix;
+ enum dwarf_form form;
size += size_of_uleb128 (die->die_abbrev);
FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
@@ -7723,7 +7979,10 @@ size_of_die (dw_die_ref die)
switch (AT_class (a))
{
case dw_val_class_addr:
- size += DWARF2_ADDR_SIZE;
+ if (dwarf_split_debug_info && AT_index (a) != -1U)
+ size += size_of_uleb128 (AT_index (a));
+ else
+ size += DWARF2_ADDR_SIZE;
break;
case dw_val_class_offset:
size += DWARF_OFFSET_SIZE;
@@ -7741,10 +8000,13 @@ size_of_die (dw_die_ref die)
}
break;
case dw_val_class_loc_list:
- size += DWARF_OFFSET_SIZE;
+ if (dwarf_split_debug_info && AT_index (a) != -1U)
+ size += size_of_uleb128 (AT_index (a));
+ else
+ size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_range_list:
- size += DWARF_OFFSET_SIZE;
+ size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_const:
size += size_of_sleb128 (AT_int (a));
@@ -7804,15 +8066,21 @@ size_of_die (dw_die_ref die)
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_lbl_id:
- size += DWARF2_ADDR_SIZE;
+ if (dwarf_split_debug_info && AT_index (a) != -1U)
+ size += size_of_uleb128 (AT_index (a));
+ else
+ size += DWARF2_ADDR_SIZE;
break;
case dw_val_class_lineptr:
case dw_val_class_macptr:
- size += DWARF_OFFSET_SIZE;
+ size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_str:
- if (AT_string_form (a) == DW_FORM_strp)
+ form = AT_string_form (a);
+ if (form == DW_FORM_strp)
size += DWARF_OFFSET_SIZE;
+ else if (form == DW_FORM_GNU_str_index)
+ size += size_of_uleb128 (AT_index (a));
else
size += strlen (a->dw_attr_val.v.val_str->str) + 1;
break;
@@ -7994,7 +8262,7 @@ size_of_aranges (void)
static enum dwarf_form
value_format (dw_attr_ref a)
{
- switch (a->dw_attr_val.val_class)
+ switch (AT_class (a))
{
case dw_val_class_addr:
/* Only very few attributes allow DW_FORM_addr. */
@@ -8004,7 +8272,8 @@ value_format (dw_attr_ref a)
case DW_AT_high_pc:
case DW_AT_entry_pc:
case DW_AT_trampoline:
- return DW_FORM_addr;
+ return (dwarf_split_debug_info && AT_index (a) != -1U
+ ? DW_FORM_GNU_addr_index : DW_FORM_addr);
default:
break;
}
@@ -8023,7 +8292,7 @@ value_format (dw_attr_ref a)
}
case dw_val_class_range_list:
case dw_val_class_loc_list:
- if (dwarf_version >= 4)
+ if (dwarf_version >= 4 || dwarf_split_debug_info)
return DW_FORM_sec_offset;
/* FALLTHRU */
case dw_val_class_vms_delta:
@@ -8120,7 +8389,8 @@ value_format (dw_attr_ref a)
case dw_val_class_fde_ref:
return DW_FORM_data;
case dw_val_class_lbl_id:
- return DW_FORM_addr;
+ return (dwarf_split_debug_info && AT_index (a) != -1U
+ ? DW_FORM_GNU_addr_index : DW_FORM_addr);
case dw_val_class_lineptr:
case dw_val_class_macptr:
return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
@@ -8157,40 +8427,46 @@ output_value_format (dw_attr_ref a)
dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
}
-/* Output the .debug_abbrev section which defines the DIE abbreviation
- table. */
+/* Given a die and id, produce the appropriate abbreviations. */
static void
-output_abbrev_section (void)
+output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
{
- unsigned long abbrev_id;
+ unsigned ix;
+ dw_attr_ref a_attr;
- for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+ dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
+ dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
+ dwarf_tag_name (abbrev->die_tag));
+
+ if (abbrev->die_child != NULL)
+ dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
+ else
+ dw2_asm_output_data (1, DW_children_no, "DW_children_no");
+
+ for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
+ ix++)
{
- dw_die_ref abbrev = abbrev_die_table[abbrev_id];
- unsigned ix;
- dw_attr_ref a_attr;
+ dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
+ dwarf_attr_name (a_attr->dw_attr));
+ output_value_format (a_attr);
+ }
+
+ dw2_asm_output_data (1, 0, NULL);
+ dw2_asm_output_data (1, 0, NULL);
+}
- dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
- dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
- dwarf_tag_name (abbrev->die_tag));
- if (abbrev->die_child != NULL)
- dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
- else
- dw2_asm_output_data (1, DW_children_no, "DW_children_no");
+/* Output the .debug_abbrev section which defines the DIE abbreviation
+ table. */
- for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
- ix++)
- {
- dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
- dwarf_attr_name (a_attr->dw_attr));
- output_value_format (a_attr);
- }
+static void
+output_abbrev_section (void)
+{
+ unsigned long abbrev_id;
- dw2_asm_output_data (1, 0, NULL);
- dw2_asm_output_data (1, 0, NULL);
- }
+ for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+ output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
/* Terminate the table. */
dw2_asm_output_data (1, 0, NULL);
@@ -8225,6 +8501,7 @@ new_loc_list (dw_loc_descr_ref expr, con
dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node ();
retlist->begin = begin;
+ retlist->begin_index = -1U;
retlist->end = end;
retlist->expr = expr;
retlist->section = section;
@@ -8269,7 +8546,22 @@ output_loc_list (dw_loc_list_ref list_he
in a single range are unlikely very useful. */
if (size > 0xffff)
continue;
- if (!have_multiple_function_sections)
+ if (dwarf_split_debug_info)
+ {
+ dw2_asm_output_data (1, DW_LLE_start_length_entry,
+ "Location list start/length entry (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_data_uleb128 (curr->begin_index,
+ "Location list range start index (%s)",
+ curr->begin);
+ /* The length field is 4 bytes. If we ever need to support
+ an 8-byte length, we can add a new DW_LLE code or fall back
+ to DW_LLE_start_end_entry. */
+ dw2_asm_output_delta (4, curr->end, curr->begin,
+ "Location list range length (%s)",
+ list_head->ll_symbol);
+ }
+ else if (!have_multiple_function_sections)
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
"Location list begin address (%s)",
@@ -8295,12 +8587,83 @@ output_loc_list (dw_loc_list_ref list_he
output_loc_sequence (curr->expr, -1);
}
- dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
- "Location list terminator begin (%s)",
- list_head->ll_symbol);
- dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
- "Location list terminator end (%s)",
- list_head->ll_symbol);
+ if (dwarf_split_debug_info)
+ dw2_asm_output_data (1, DW_LLE_end_of_list_entry,
+ "Location list terminator (%s)",
+ list_head->ll_symbol);
+ else
+ {
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+ "Location list terminator begin (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+ "Location list terminator end (%s)",
+ list_head->ll_symbol);
+ }
+}
+
+/* Output the offset into the debug_range section. */
+
+static void
+output_range_list_offset (dw_attr_ref a)
+{
+ const char *name = dwarf_attr_name (a->dw_attr);
+
+ if (!dwarf_split_debug_info || AT_index (a) == -1U)
+ {
+ char *p = strchr (ranges_section_label, '\0');
+ sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
+ debug_ranges_section, "%s", name);
+ *p = '\0';
+ }
+ else
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
+ "%s (offset from %s)", name, ranges_section_label);
+}
+
+/* Output the offset into the debug_loc section. */
+
+static void
+output_loc_list_offset (dw_attr_ref a)
+{
+ char *sym = AT_loc_list (a)->ll_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
+output_attr_index_or_value (dw_attr_ref a)
+{
+ const char *name = dwarf_attr_name (a->dw_attr);
+
+ if (dwarf_split_debug_info && AT_index (a) != -1U)
+ {
+ dw2_asm_output_data_uleb128 (AT_index (a), "%s", name);
+ return;
+ }
+ switch (AT_class (a))
+ {
+ case dw_val_class_addr:
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
+ break;
+ case dw_val_class_lbl_id:
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
+ break;
+ case dw_val_class_loc_list:
+ output_loc_list_offset (a);
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
/* Output a type signature. */
@@ -8341,7 +8704,7 @@ output_die (dw_die_ref die)
switch (AT_class (a))
{
case dw_val_class_addr:
- dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
+ output_attr_index_or_value (a);
break;
case dw_val_class_offset:
@@ -8350,15 +8713,7 @@ output_die (dw_die_ref die)
break;
case dw_val_class_range_list:
- {
- char *p = strchr (ranges_section_label, '\0');
-
- sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
- a->dw_attr_val.v.val_offset);
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
- debug_ranges_section, "%s", name);
- *p = '\0';
- }
+ output_range_list_offset (a);
break;
case dw_val_class_loc:
@@ -8414,7 +8769,7 @@ output_die (dw_die_ref die)
}
dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
- first, name);
+ first, "%s", name);
dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
second, NULL);
}
@@ -8461,13 +8816,7 @@ output_die (dw_die_ref die)
break;
case dw_val_class_loc_list:
- {
- char *sym = AT_loc_list (a)->ll_symbol;
-
- gcc_assert (sym);
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
- "%s", name);
- }
+ output_attr_index_or_value (a);
break;
case dw_val_class_die_ref:
@@ -8524,7 +8873,7 @@ output_die (dw_die_ref die)
break;
case dw_val_class_lbl_id:
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
+ output_attr_index_or_value (a);
break;
case dw_val_class_lineptr:
@@ -8538,12 +8887,15 @@ output_die (dw_die_ref die)
break;
case dw_val_class_str:
- if (AT_string_form (a) == DW_FORM_strp)
+ if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
dw2_asm_output_offset (DWARF_OFFSET_SIZE,
a->dw_attr_val.v.val_str->label,
debug_str_section,
"%s: \"%s\"", name, AT_string (a));
- else
+ else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
+ dw2_asm_output_data_uleb128 (AT_index (a),
+ "%s: \"%s\"", name, AT_string (a));
+ else
dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
break;
@@ -8683,6 +9035,103 @@ add_AT_pubnames (dw_die_ref die)
}
}
+/* Helper function to generate top-level dies for skeleton debug_info and
+ debug_types. */
+
+static void
+add_top_level_skeleton_die_attrs (dw_die_ref die)
+{
+ const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL);
+ dw_attr_ref attr;
+
+ add_comp_dir_attribute (die);
+ add_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name);
+ /* The specification suggests that these attributes be inline to avoid
+ having a .debug_str section. We know that they exist in the die because
+ we just added them. */
+ attr = get_AT (die, DW_AT_GNU_dwo_name);
+ attr->dw_attr_val.v.val_str->form = DW_FORM_string;
+ attr = get_AT (die, DW_AT_comp_dir);
+ attr->dw_attr_val.v.val_str->form = DW_FORM_string;
+
+ add_AT_pubnames (die);
+ add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label);
+}
+
+/* Return the single type-unit die for skeleton type units. */
+
+static dw_die_ref
+get_skeleton_type_unit (void)
+{
+ /* For split_debug_sections with use_type info, all type units int the
+ skeleton sections have identical dies (but different headers). This single
+ die will be output many times. */
+
+ static dw_die_ref skeleton_type_unit = NULL;
+
+ if (skeleton_type_unit == NULL)
+ {
+ skeleton_type_unit = new_die (DW_TAG_type_unit, NULL, NULL);
+ add_top_level_skeleton_die_attrs (skeleton_type_unit);
+ skeleton_type_unit->die_abbrev = SKELETON_TYPE_DIE_ABBREV;
+ }
+ return skeleton_type_unit;
+}
+
+/* The splitter will fill in this value. */
+
+unsigned char dwo_id_placeholder[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* Output skeleton debug sections that point to the dwo file. */
+
+static void
+output_skeleton_debug_sections (dw_die_ref comp_unit)
+{
+ /* These attributes will be found in the full debug_info section. */
+ remove_AT (comp_unit, DW_AT_producer);
+ remove_AT (comp_unit, DW_AT_language);
+
+ /* Add attributes common to skeleton compile_units and type_units. */
+ add_top_level_skeleton_die_attrs (comp_unit);
+
+ /* The dwo_id is only for compile_units. */
+ add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder);
+
+ switch_to_section (debug_skeleton_info_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label);
+
+ /* Produce the skeleton compilation-unit header. This one differs enough from
+ a normal CU header that it's better not to call output_compilation_unit
+ header. */
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+
+ dw2_asm_output_data (DWARF_OFFSET_SIZE,
+ DWARF_COMPILE_UNIT_HEADER_SIZE
+ - DWARF_INITIAL_LENGTH_SIZE
+ + size_of_die (comp_unit),
+ "Length of Compilation Unit Info");
+ dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
+ debug_abbrev_section,
+ "Offset Into Abbrev. Section");
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+
+ comp_unit->die_abbrev = 1;
+ output_die (comp_unit);
+
+ /* Build the skeleton debug_abbrev section. */
+ switch_to_section (debug_skeleton_abbrev_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label);
+
+ output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit);
+ if (use_debug_types)
+ output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, get_skeleton_type_unit ());
+
+ dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev");
+}
+
/* Output a comdat type unit DIE and its children. */
static void
@@ -8705,7 +9154,11 @@ output_comdat_type_unit (comdat_type_nod
calc_die_sizes (node->root_die);
#if defined (OBJECT_FORMAT_ELF)
- secname = ".debug_types";
+ if (!dwarf_split_debug_info)
+ secname = ".debug_types";
+ else
+ secname = ".debug_types.dwo";
+
tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
sprintf (tmp, "wt.");
for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
@@ -8714,6 +9167,7 @@ output_comdat_type_unit (comdat_type_nod
targetm.asm_out.named_section (secname,
SECTION_DEBUG | SECTION_LINKONCE,
comdat_key);
+
#else
tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
sprintf (tmp, ".gnu.linkonce.wt.");
@@ -8731,6 +9185,37 @@ output_comdat_type_unit (comdat_type_nod
output_die (node->root_die);
unmark_dies (node->root_die);
+
+ if (dwarf_split_debug_info)
+ {
+ /* Produce the skeleton type-unit header. */
+ const char *secname = ".debug_types";
+
+ targetm.asm_out.named_section (secname,
+ SECTION_DEBUG | SECTION_LINKONCE,
+ comdat_key);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+
+ /* One for the terminating NULL byte. */
+ dw2_asm_output_data (DWARF_OFFSET_SIZE,
+ DWARF_COMPILE_UNIT_HEADER_SIZE
+ - DWARF_INITIAL_LENGTH_SIZE
+ + size_of_die (get_skeleton_type_unit ())
+ + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE,
+ "Length of Type Unit Info");
+ dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+ debug_skeleton_abbrev_section_label,
+ debug_abbrev_section,
+ "Offset Into Abbrev. Section");
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+ output_signature (node->signature, "Type Signature");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Offset to Type DIE");
+
+ output_die (get_skeleton_type_unit ());
+ }
}
/* Return the DWARF2/3 pubname associated with a decl. */
@@ -8880,9 +9365,14 @@ output_pubnames (VEC (pubname_entry, gc)
"Length of Public Type Names Info");
/* Version number for pubnames/pubtypes is still 2, even in DWARF3. */
dw2_asm_output_data (2, 2, "DWARF Version");
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
- debug_info_section,
- "Offset of Compilation Unit Info");
+ if (dwarf_split_debug_info)
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
+ debug_skeleton_info_section,
+ "Offset of Compilation Unit Info");
+ else
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+ debug_info_section,
+ "Offset of Compilation Unit Info");
dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
"Compilation Unit Length");
@@ -8937,9 +9427,14 @@ output_aranges (unsigned long aranges_le
"Length of Address Ranges Info");
/* Version number for aranges is still 2, even in DWARF3. */
dw2_asm_output_data (2, 2, "DWARF Version");
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
- debug_info_section,
- "Offset of Compilation Unit Info");
+ if (dwarf_split_debug_info)
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
+ debug_skeleton_info_section,
+ "Offset of Compilation Unit Info");
+ else
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+ debug_info_section,
+ "Offset of Compilation Unit Info");
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
@@ -9039,7 +9534,7 @@ add_ranges (const_tree block)
static void
add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
- bool *added)
+ bool *added, bool force_direct)
{
unsigned int in_use = ranges_by_label_in_use;
unsigned int offset;
@@ -9062,7 +9557,7 @@ add_ranges_by_labels (dw_die_ref die, co
offset = add_ranges_num (-(int)in_use - 1);
if (!*added)
{
- add_AT_range_list (die, DW_AT_ranges, offset);
+ add_AT_range_list (die, DW_AT_ranges, offset, force_direct);
*added = true;
}
}
@@ -9599,7 +10094,7 @@ output_one_line_info_table (dw_line_info
information goes into the .debug_line section. */
static void
-output_line_info (void)
+output_line_info (bool prologue_only)
{
char l1[20], l2[20], p1[20], p2[20];
int ver = dwarf_version;
@@ -9669,6 +10164,12 @@ output_line_info (void)
/* Write out the information about the files we use. */
output_file_names ();
ASM_OUTPUT_LABEL (asm_out_file, p2);
+ if (prologue_only)
+ {
+ /* Output the marker for the end of the line number info. */
+ ASM_OUTPUT_LABEL (asm_out_file, l2);
+ return;
+ }
if (separate_line_info)
{
@@ -11975,14 +12476,7 @@ mem_loc_descriptor (rtx rtl, enum machin
if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
break;
- /* We used to emit DW_OP_addr here, but that's wrong, since
- DW_OP_addr should be relocated by the debug info consumer,
- while DW_OP_GNU_push_tls_address operand should not. */
- temp = new_loc_descr (DWARF2_ADDR_SIZE == 4
- ? DW_OP_const4u : DW_OP_const8u, 0, 0);
- temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
- temp->dw_loc_oprnd1.v.val_addr = rtl;
- temp->dtprel = true;
+ temp = new_addr_loc_descr (rtl, true);
mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
add_loc_descr (&mem_loc_result, temp);
@@ -11994,9 +12488,7 @@ mem_loc_descriptor (rtx rtl, enum machin
break;
symref:
- mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
- mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
- mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+ mem_loc_result = new_addr_loc_descr (rtl, 0);
VEC_safe_push (rtx, gc, used_rtx_array, rtl);
break;
@@ -12898,9 +13390,7 @@ loc_descriptor (rtx rtl, enum machine_mo
if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
&& (dwarf_version >= 4 || !dwarf_strict))
{
- loc_result = new_loc_descr (DW_OP_addr, 0, 0);
- loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
- loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+ loc_result = new_addr_loc_descr (rtl, 0);
add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
VEC_safe_push (rtx, gc, used_rtx_array, rtl);
}
@@ -13601,8 +14091,7 @@ loc_list_from_tree (tree loc, int want_a
if (DECL_THREAD_LOCAL_P (loc))
{
rtx rtl;
- enum dwarf_location_atom first_op;
- enum dwarf_location_atom second_op;
+ enum dwarf_location_atom tls_op;
bool dtprel = false;
if (targetm.have_tls)
@@ -13620,9 +14109,8 @@ loc_list_from_tree (tree loc, int want_a
operand shouldn't be. */
if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
return 0;
- first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u;
dtprel = true;
- second_op = DW_OP_GNU_push_tls_address;
+ tls_op = DW_OP_GNU_push_tls_address;
}
else
{
@@ -13634,8 +14122,7 @@ loc_list_from_tree (tree loc, int want_a
no longer appear in gimple code. We used the control
variable in specific so that we could pick it up here. */
loc = DECL_VALUE_EXPR (loc);
- first_op = DW_OP_addr;
- second_op = DW_OP_form_tls_address;
+ tls_op = DW_OP_form_tls_address;
}
rtl = rtl_for_decl_location (loc);
@@ -13648,12 +14135,8 @@ loc_list_from_tree (tree loc, int want_a
if (! CONSTANT_P (rtl))
return 0;
- ret = new_loc_descr (first_op, 0, 0);
- ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
- ret->dw_loc_oprnd1.v.val_addr = rtl;
- ret->dtprel = dtprel;
-
- ret1 = new_loc_descr (second_op, 0, 0);
+ ret = new_addr_loc_descr (rtl, dtprel);
+ ret1 = new_loc_descr (tls_op, 0, 0);
add_loc_descr (&ret, ret1);
have_address = 1;
@@ -13698,11 +14181,7 @@ loc_list_from_tree (tree loc, int want_a
return 0;
}
else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
- {
- ret = new_loc_descr (DW_OP_addr, 0, 0);
- ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
- ret->dw_loc_oprnd1.v.val_addr = rtl;
- }
+ ret = new_addr_loc_descr (rtl, 0);
else
{
enum machine_mode mode, mem_mode;
@@ -14640,9 +15119,7 @@ add_const_value_attribute (dw_die_ref di
dw_loc_descr_ref loc_result;
resolve_one_addr (&rtl, NULL);
rtl_addr:
- loc_result = new_loc_descr (DW_OP_addr, 0, 0);
- loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
- loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+ loc_result = new_addr_loc_descr (rtl, 0);
add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
add_AT_loc (die, DW_AT_location, loc_result);
VEC_safe_push (rtx, gc, used_rtx_array, rtl);
@@ -16151,7 +16628,7 @@ add_name_and_src_coords_attributes (dw_d
if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
{
add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
- XEXP (DECL_RTL (decl), 0));
+ XEXP (DECL_RTL (decl), 0), false);
VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
}
#endif /* VMS_DEBUGGING_INFO */
@@ -16172,7 +16649,7 @@ dwarf2out_vms_debug_main_pointer (void)
add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
FUNC_LABEL_ID (cfun));
- add_AT_lbl_id (die, DW_AT_entry_pc, label);
+ add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
/* Make it the first child of comp_unit_die (). */
die->die_parent = comp_unit_die ();
@@ -16759,7 +17236,7 @@ gen_entry_point_die (tree decl, dw_die_r
if (DECL_ABSTRACT (decl))
equate_decl_number_to_die (decl, decl_die);
else
- add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
+ add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl), false);
}
#endif
@@ -17280,7 +17757,7 @@ gen_call_site_die (tree decl, dw_die_ref
if (stmt_die == NULL)
stmt_die = subr_die;
die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
- add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
+ add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label, false);
if (ca_loc->tail_call_p)
add_AT_flag (die, DW_AT_GNU_tail_call, 1);
if (ca_loc->symbol_ref)
@@ -17289,7 +17766,7 @@ gen_call_site_die (tree decl, dw_die_ref
if (tdie)
add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
else
- add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
+ add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
}
return die;
}
@@ -17480,8 +17957,8 @@ gen_subprogram_die (tree decl, dw_die_re
if (fde->dw_fde_begin)
{
/* We have already generated the labels. */
- add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin);
- add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end);
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false);
}
else
{
@@ -17489,10 +17966,10 @@ gen_subprogram_die (tree decl, dw_die_re
char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
FUNC_LABEL_ID (cfun));
- add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id, false);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
FUNC_LABEL_ID (cfun));
- add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id, false);
}
#if VMS_DEBUGGING_INFO
@@ -17535,10 +18012,11 @@ gen_subprogram_die (tree decl, dw_die_re
alignment offset. */
bool range_list_added = false;
add_ranges_by_labels (subr_die, fde->dw_fde_begin,
- fde->dw_fde_end, &range_list_added);
+ fde->dw_fde_end, &range_list_added,
+ false);
add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
fde->dw_fde_second_end,
- &range_list_added);
+ &range_list_added, false);
if (range_list_added)
add_ranges (NULL);
}
@@ -17557,9 +18035,9 @@ gen_subprogram_die (tree decl, dw_die_re
/* Do the 'primary' section. */
add_AT_lbl_id (subr_die, DW_AT_low_pc,
- fde->dw_fde_begin);
+ fde->dw_fde_begin, false);
add_AT_lbl_id (subr_die, DW_AT_high_pc,
- fde->dw_fde_end);
+ fde->dw_fde_end, false);
/* Build a minimal DIE for the secondary section. */
seg_die = new_die (DW_TAG_subprogram,
@@ -17584,9 +18062,9 @@ gen_subprogram_die (tree decl, dw_die_re
name = concat ("__second_sect_of_", name, NULL);
add_AT_lbl_id (seg_die, DW_AT_low_pc,
- fde->dw_fde_second_begin);
+ fde->dw_fde_second_begin, false);
add_AT_lbl_id (seg_die, DW_AT_high_pc,
- fde->dw_fde_second_end);
+ fde->dw_fde_second_end, false);
add_name_attribute (seg_die, name);
if (want_pubnames ())
add_pubname_string (name, seg_die);
@@ -17594,8 +18072,8 @@ gen_subprogram_die (tree decl, dw_die_re
}
else
{
- add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin);
- add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end);
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false);
}
}
@@ -18039,7 +18517,7 @@ gen_variable_die (tree decl, tree origin
{
/* Optimize the common case. */
if (single_element_loc_list_p (loc)
- && loc->expr->dw_loc_opc == DW_OP_addr
+ && loc->expr->dw_loc_opc == DW_OP_addr
&& loc->expr->dw_loc_next == NULL
&& GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
loc->expr->dw_loc_oprnd1.v.val_addr
@@ -18223,7 +18701,7 @@ gen_label_die (tree decl, dw_die_ref con
gcc_assert (!INSN_DELETED_P (insn));
ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
- add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+ add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
}
else if (insn
&& NOTE_P (insn)
@@ -18231,7 +18709,7 @@ gen_label_die (tree decl, dw_die_ref con
&& 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);
+ add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
}
}
}
@@ -18270,10 +18748,10 @@ add_high_low_attributes (tree stmt, dw_d
{
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
BLOCK_NUMBER (stmt));
- add_AT_lbl_id (die, DW_AT_entry_pc, label);
+ add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
}
- add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
+ add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
chain = BLOCK_FRAGMENT_CHAIN (stmt);
do
@@ -18288,10 +18766,10 @@ add_high_low_attributes (tree stmt, dw_d
{
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
BLOCK_NUMBER (stmt));
- add_AT_lbl_id (die, DW_AT_low_pc, label);
+ add_AT_lbl_id (die, DW_AT_low_pc, label, false);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
BLOCK_NUMBER (stmt));
- add_AT_lbl_id (die, DW_AT_high_pc, label);
+ add_AT_lbl_id (die, DW_AT_high_pc, label, false);
}
}
@@ -20943,6 +21421,7 @@ output_macinfo_op (macinfo_entry *ref)
case DW_MACRO_GNU_define_indirect:
case DW_MACRO_GNU_undef_indirect:
node = find_AT_string (ref->info);
+ /* FIXME: needs to change for dwarf_split_debug_info. */
if (node->form != DW_FORM_strp)
{
char label[32];
@@ -21130,8 +21609,10 @@ output_macinfo (void)
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);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+ (!dwarf_split_debug_info ? debug_line_section_label
+ : debug_skeleton_line_section_label),
+ debug_line_section, NULL);
}
/* In the first loop, it emits the primary .debug_macinfo section
@@ -21270,26 +21751,60 @@ dwarf2out_init (const char *filename ATT
used_rtx_array = VEC_alloc (rtx, gc, 32);
- debug_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
+ if (!dwarf_split_debug_info)
+ {
+ debug_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_loc_section = get_section (DEBUG_LOC_SECTION,
+ SECTION_DEBUG, NULL);
+ }
+ else
+ {
+ debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_addr_section = get_section (DEBUG_ADDR_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+ DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
+
+ /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
+ the main .o, but the skeleton_line goes into the split off dwo. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_DWO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL, 0);
+ debug_str_offsets_section = get_section (DEBUG_STR_OFFSETS_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+ DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
+ debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ }
debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
SECTION_DEBUG, NULL);
debug_macinfo_section = get_section (dwarf_strict
? DEBUG_MACINFO_SECTION
: DEBUG_MACRO_SECTION,
- SECTION_DEBUG, NULL);
+ DEBUG_MACRO_SECTION_FLAGS, NULL);
debug_line_section = get_section (DEBUG_LINE_SECTION,
SECTION_DEBUG, NULL);
- debug_loc_section = get_section (DEBUG_LOC_SECTION,
- SECTION_DEBUG, NULL);
debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
SECTION_DEBUG, NULL);
debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
SECTION_DEBUG, NULL);
debug_str_section = get_section (DEBUG_STR_SECTION,
- DEBUG_STR_SECTION_FLAGS, NULL);
+ DEBUG_STR_SECTION_FLAGS, NULL);
debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
SECTION_DEBUG, NULL);
debug_frame_section = get_section (DEBUG_FRAME_SECTION,
@@ -21313,10 +21828,13 @@ dwarf2out_init (const char *filename ATT
DEBUG_LINE_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
DEBUG_RANGES_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
+ DEBUG_ADDR_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
dwarf_strict
? DEBUG_MACINFO_SECTION_LABEL
: DEBUG_MACRO_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
@@ -21360,6 +21878,79 @@ output_indirect_string (void **h, void *
return 1;
}
+static void
+output_index_strings (void)
+{
+ unsigned int i;
+ unsigned int len = 0;
+ struct indirect_string_node *node;
+
+ if (VEC_empty (indirect_string_node, index_string_table))
+ return;
+
+ switch_to_section (debug_str_offsets_section);
+ for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
+ i++)
+ {
+ gcc_assert (node->form == DW_FORM_GNU_str_index);
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, len,
+ "indexed string 0x%x: %s", i, node->str);
+ len += strlen (node->str) + 1;
+ }
+ switch_to_section (debug_str_section);
+ for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
+ i++)
+ {
+ ASM_OUTPUT_LABEL (asm_out_file, node->label);
+ assemble_string (node->str, strlen (node->str) + 1);
+ }
+}
+
+/* Write the index table. */
+
+static void
+output_addr_table (void)
+{
+ unsigned int i;
+ dw_attr_node *node;
+
+ if (VEC_empty (dw_attr_node, addr_index_table))
+ return;
+
+ switch_to_section (debug_addr_section);
+ for (i = 0; VEC_iterate (dw_attr_node, addr_index_table, i, node); i++)
+ {
+ const char *name;
+
+ if (node->dw_attr == 0)
+ {
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, "<Removed entry>");
+ continue;
+ }
+
+ name = dwarf_attr_name (node->dw_attr);
+ switch (AT_class (node))
+ {
+ case dw_val_class_addr:
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (node),
+ "%s", name);
+ break;
+ case dw_val_class_loc:
+ gcc_assert (targetm.asm_out.output_dwarf_dtprel);
+ targetm.asm_out.output_dwarf_dtprel (asm_out_file,
+ DWARF2_ADDR_SIZE,
+ node->dw_attr_val.v.val_addr);
+ fputc ('\n', asm_out_file);
+ break;
+ case dw_val_class_lbl_id:
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+}
+
#if ENABLE_ASSERT_CHECKING
/* Verify that all marks are clear. */
@@ -21964,6 +22555,17 @@ resolve_addr_in_expr (dw_loc_descr_ref l
if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
return false;
break;
+ case DW_OP_GNU_addr_index:
+ case DW_OP_GNU_const_index:
+ {
+ unsigned int idx = loc->dw_loc_oprnd1.val_index;
+ dw_attr_node *node = VEC_index (dw_attr_node, addr_index_table, idx);
+ if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
+ || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
+ && resolve_one_addr (&node->dw_attr_val.v.val_addr, NULL))
+ return false;
+ }
+ break;
case DW_OP_const4u:
case DW_OP_const8u:
if (loc->dtprel
@@ -22098,11 +22700,15 @@ resolve_addr (dw_die_ref die)
if (!resolve_addr_in_expr ((*curr)->expr))
{
dw_loc_list_ref next = (*curr)->dw_loc_next;
+ dw_loc_descr_ref l = (*curr)->expr;
+
if (next && (*curr)->ll_symbol)
{
gcc_assert (!next->ll_symbol);
next->ll_symbol = (*curr)->ll_symbol;
}
+ if (l->dw_loc_oprnd1.val_index != -1U)
+ remove_addr_table_entry (l->dw_loc_oprnd1.val_index);
*curr = next;
}
else
@@ -22116,6 +22722,8 @@ resolve_addr (dw_die_ref die)
else
{
loc->replaced = 1;
+ if (dwarf_split_debug_info)
+ remove_loc_list_addr_table_entries (loc);
loc->dw_loc_next = *start;
}
}
@@ -22140,6 +22748,8 @@ resolve_addr (dw_die_ref die)
|| l->dw_loc_next != NULL)
&& !resolve_addr_in_expr (l))
{
+ if (l->dw_loc_oprnd1.val_index != -1U)
+ remove_addr_table_entry (l->dw_loc_oprnd1.val_index);
remove_AT (die, a->dw_attr);
ix--;
}
@@ -22151,6 +22761,8 @@ resolve_addr (dw_die_ref die)
if (a->dw_attr == DW_AT_const_value
&& resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
{
+ if (AT_index (a) != -1U)
+ remove_addr_table_entry (AT_index (a));
remove_AT (die, a->dw_attr);
ix--;
}
@@ -22174,6 +22786,8 @@ resolve_addr (dw_die_ref die)
}
else
{
+ if (AT_index (a) != -1U)
+ remove_addr_table_entry (AT_index (a));
remove_AT (die, a->dw_attr);
ix--;
}
@@ -22307,6 +22921,19 @@ hash_loc_operands (dw_loc_descr_ref loc,
}
hash = iterative_hash_rtx (val1->v.val_addr, hash);
break;
+ case DW_OP_GNU_addr_index:
+ case DW_OP_GNU_const_index:
+ {
+ dw_attr_ref attr = VEC_index (dw_attr_node, addr_index_table,
+ val1->val_index);
+ if (loc->dtprel)
+ {
+ unsigned char dtprel = 0xd1;
+ hash = iterative_hash_object (dtprel, hash);
+ }
+ hash = iterative_hash_rtx (attr->dw_attr_val.v.val_addr, hash);
+ }
+ break;
case DW_OP_GNU_implicit_pointer:
hash = iterative_hash_object (val2->v.val_int, hash);
break;
@@ -22488,9 +23115,12 @@ compare_loc_operands (dw_loc_descr_ref x
return valx1->v.val_int == valy1->v.val_int;
case DW_OP_skip:
case DW_OP_bra:
+ /* If splitting debug info, the use of DW_OP_GNU_addr_index
+ can cause irrelevant differences in dw_loc_addr. */
gcc_assert (valx1->val_class == dw_val_class_loc
&& valy1->val_class == dw_val_class_loc
- && x->dw_loc_addr == y->dw_loc_addr);
+ && (dwarf_split_debug_info
+ || x->dw_loc_addr == y->dw_loc_addr));
return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
case DW_OP_implicit_value:
if (valx1->v.val_unsigned != valy1->v.val_unsigned
@@ -22521,6 +23151,18 @@ compare_loc_operands (dw_loc_descr_ref x
case DW_OP_addr:
hash_addr:
return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
+ case DW_OP_GNU_addr_index:
+ case DW_OP_GNU_const_index:
+ {
+ dw_attr_node *attrx1 = VEC_index (dw_attr_node,
+ addr_index_table,
+ valx1->val_index);
+ dw_attr_node *attry1 = VEC_index (dw_attr_node,
+ addr_index_table,
+ valy1->val_index);
+ return rtx_equal_p (attrx1->dw_attr_val.v.val_addr,
+ attry1->dw_attr_val.v.val_addr);
+ }
case DW_OP_GNU_implicit_pointer:
return valx1->val_class == dw_val_class_die_ref
&& valx1->val_class == valy1->val_class
@@ -22634,7 +23276,7 @@ optimize_location_lists_1 (dw_die_ref di
if (*slot == NULL)
*slot = (void *) list;
else
- a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
+ a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
}
FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
@@ -22650,6 +23292,43 @@ optimize_location_lists (dw_die_ref die)
optimize_location_lists_1 (die, htab);
htab_delete (htab);
}
+
+
+/* Recursively assign each location list a unique index into the debug_addr
+ section. */
+
+static void
+index_location_lists (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_attr_ref a;
+ unsigned ix;
+
+ FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+ if (AT_class (a) == dw_val_class_loc_list)
+ {
+ dw_loc_list_ref list = AT_loc_list (a);
+ dw_loc_list_ref curr;
+ for (curr = list; curr != NULL; curr = curr->dw_loc_next)
+ {
+ dw_attr_node attr;
+
+ /* Don't index an entry that has already been indexed
+ or won't be output. */
+ if (curr->begin_index != -1U
+ || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
+ continue;
+
+ attr.dw_attr = DW_AT_location;
+ attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+ attr.dw_attr_val.val_index = -1U;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (curr->begin);
+ curr->begin_index = add_addr_table_entry (&attr);
+ }
+ }
+
+ FOR_EACH_CHILD (die, c, index_location_lists (c));
+}
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
@@ -22661,6 +23340,7 @@ dwarf2out_finish (const char *filename)
comdat_type_node *ctnode;
htab_t comdat_type_table;
unsigned int i;
+ dw_die_ref main_comp_unit_die;
/* PCH might result in DW_AT_producer string being restored from the
header compilation, fix it up if needed. */
@@ -22814,6 +23494,14 @@ dwarf2out_finish (const char *filename)
for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
add_sibling_attributes (ctnode->root_die);
+ /* When splitting DWARF info, we put some attributes in the
+ skeleton compile_unit DIE that remains in the .o, while
+ most attributes go in the DWO compile_unit_die. */
+ if (dwarf_split_debug_info)
+ main_comp_unit_die = gen_compile_unit_die (NULL);
+ else
+ main_comp_unit_die = comp_unit_die ();
+
/* Output a terminator label for the .text section. */
switch_to_section (text_section);
targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
@@ -22831,8 +23519,10 @@ dwarf2out_finish (const char *filename)
/* Don't add if the CU has no associated code. */
if (text_section_used)
{
- add_AT_lbl_id (comp_unit_die (), DW_AT_low_pc, text_section_label);
- add_AT_lbl_id (comp_unit_die (), DW_AT_high_pc, text_end_label);
+ add_AT_lbl_id (main_comp_unit_die, DW_AT_low_pc, text_section_label,
+ true);
+ add_AT_lbl_id (main_comp_unit_die, DW_AT_high_pc, text_end_label,
+ true);
}
}
else
@@ -22842,20 +23532,22 @@ dwarf2out_finish (const char *filename)
bool range_list_added = false;
if (text_section_used)
- add_ranges_by_labels (comp_unit_die (), text_section_label,
- text_end_label, &range_list_added);
+ add_ranges_by_labels (main_comp_unit_die, text_section_label,
+ text_end_label, &range_list_added, true);
if (cold_text_section_used)
- add_ranges_by_labels (comp_unit_die (), cold_text_section_label,
- cold_end_label, &range_list_added);
+ add_ranges_by_labels (main_comp_unit_die, cold_text_section_label,
+ cold_end_label, &range_list_added, true);
FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
{
if (!fde->in_std_section)
- add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin,
- fde->dw_fde_end, &range_list_added);
+ add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin,
+ fde->dw_fde_end, &range_list_added,
+ true);
if (fde->dw_fde_second_begin && !fde->second_in_std_section)
- add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin,
- fde->dw_fde_second_end, &range_list_added);
+ add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_second_begin,
+ fde->dw_fde_second_end, &range_list_added,
+ true);
}
if (range_list_added)
@@ -22865,16 +23557,16 @@ dwarf2out_finish (const char *filename)
absolute. Historically, we've emitted the unexpected
DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
Emit both to give time for other tools to adapt. */
- add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx);
+ add_AT_addr (main_comp_unit_die, DW_AT_low_pc, const0_rtx, true);
if (! dwarf_strict && dwarf_version < 4)
- add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx);
+ add_AT_addr (main_comp_unit_die, DW_AT_entry_pc, const0_rtx, true);
add_ranges (NULL);
}
}
if (generate_debug_line_table)
- add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list,
+ add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list,
debug_line_section_label);
if (have_macinfo)
@@ -22883,7 +23575,11 @@ dwarf2out_finish (const char *filename)
macinfo_section_label);
if (have_location_lists)
- optimize_location_lists (comp_unit_die ());
+ {
+ optimize_location_lists (comp_unit_die ());
+ if (dwarf_split_debug_info)
+ index_location_lists (comp_unit_die ());
+ }
/* Output all of the compilation units. We put the main one last so that
the offsets are available to output_pubnames. */
@@ -22904,19 +23600,34 @@ dwarf2out_finish (const char *filename)
attributes. */
if (generate_debug_line_table)
add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
- debug_line_section_label);
+ (!dwarf_split_debug_info
+ ? debug_line_section_label
+ : debug_skeleton_line_section_label));
output_comdat_type_unit (ctnode);
*slot = ctnode;
}
htab_delete (comdat_type_table);
- add_AT_pubnames (comp_unit_die ());
+ if (!dwarf_split_debug_info)
+ add_AT_pubnames (comp_unit_die ());
+
+ if (dwarf_split_debug_info)
+ {
+ /* Add a place-holder for the dwo_id to the comp-unit die. */
+ add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, dwo_id_placeholder);
+ if (ranges_table_in_use)
+ add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
+ ranges_section_label);
+ }
/* Output the main compilation unit if non-empty or if .debug_macinfo
or .debug_macro will be emitted. */
output_comp_unit (comp_unit_die (), have_macinfo);
+ if (dwarf_split_debug_info && info_section_emitted)
+ output_skeleton_debug_sections (main_comp_unit_die);
+
/* Output the abbreviation table. */
if (abbrev_die_table_in_use != 1)
{
@@ -22930,8 +23641,6 @@ dwarf2out_finish (const char *filename)
{
/* Output the location lists info. */
switch_to_section (debug_loc_section);
- ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
- DEBUG_LOC_SECTION_LABEL, 0);
ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
output_location_lists (comp_unit_die ());
}
@@ -22982,10 +23691,22 @@ dwarf2out_finish (const char *filename)
switch_to_section (debug_line_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
if (! DWARF2_ASM_LINE_DEBUG_INFO)
- output_line_info ();
+ output_line_info (false);
+
+ if (dwarf_split_debug_info && info_section_emitted)
+ {
+ switch_to_section (debug_skeleton_line_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
+ output_line_info (true);
+
+ output_index_strings ();
+
+ switch_to_section (debug_addr_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
+ output_addr_table ();
+ }
- /* If we emitted any DW_FORM_strp form attribute, output the string
- table too. */
+ /* If we emitted any indirect strings, output the string table too. */
if (debug_str_hash)
htab_traverse (debug_str_hash, output_indirect_string, NULL);
}
===================================================================
@@ -171,6 +171,7 @@ dw_vec_const;
typedef struct GTY(()) dw_val_struct {
enum dw_val_class val_class;
+ unsigned int val_index;
union dw_val_struct_union
{
rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
===================================================================
@@ -865,6 +865,10 @@ finish_options (struct gcc_options *opts
/* Turn on -ffunction-sections when -freorder-functions=* is used. */
if (opts->x_flag_reorder_functions > 1)
opts->x_flag_function_sections = 1;
+
+ /* The -gsplit-dwarf option requires -gpubnames. */
+ if (opts->x_dwarf_split_debug_info)
+ opts->x_debug_generate_pub_sections = 1;
}
#define LEFT_COLUMN 27
@@ -1776,6 +1780,11 @@ common_handle_option (struct gcc_options
set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc);
break;
+ case OPT_gsplit_dwarf:
+ set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set,
+ loc);
+ break;
+
case OPT_ggdb:
set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc);
break;
===================================================================
@@ -2432,6 +2432,14 @@ grecord-gcc-switches
Common RejectNegative Var(dwarf_record_gcc_switches,1)
Record gcc command line switches in DWARF DW_AT_producer.
+gno-split-dwarf
+Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
+Don't generate debug information in separate .dwo files
+
+gsplit-dwarf
+Common Driver RejectNegative Var(dwarf_split_debug_info,1)
+Generate debug information in separate .dwo files
+
gstabs
Common JoinedOrMissing Negative(gstabs+)
Generate debug information in STABS format